linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V3 0/3] Add new PowerPC specific ELF core notes
@ 2014-05-23 15:15 Anshuman Khandual
  2014-05-23 15:15 ` [PATCH V3 1/3] elf: Add some new PowerPC specifc note sections Anshuman Khandual
                   ` (5 more replies)
  0 siblings, 6 replies; 19+ messages in thread
From: Anshuman Khandual @ 2014-05-23 15:15 UTC (permalink / raw)
  To: linux-kernel, linuxppc-dev, peterz, akpm, tglx
  Cc: mikey, james.hogan, avagin, Paul.Clothier, palves, oleg,
	dhowells, davej, davem

	This patch series adds five new ELF core note sections which can be
used with existing ptrace request PTRACE_GETREGSET/SETREGSET for accessing
various transactional memory and miscellaneous register sets on PowerPC
platform. Please find a test program exploiting these new ELF core note
types on a POWER8 system.

RFC: https://lkml.org/lkml/2014/4/1/292
V1:  https://lkml.org/lkml/2014/4/2/43
V2:  https://lkml.org/lkml/2014/5/5/88

Changes in V3
=============
(1) Added two new error paths in every TM related get/set functions when regset
    support is not present on the system (ENODEV) or when the process does not
    have any transaction active (ENODATA) in the context

(2) Installed the active hooks for all the newly added regset core note types

Changes in V2
=============
(1) Removed all the power specific ptrace requests corresponding to new NT_PPC_*
    elf core note types. Now all the register sets can be accessed from ptrace
    through PTRACE_GETREGSET/PTRACE_SETREGSET using the individual NT_PPC* core
    note type instead
(2) Fixed couple of attribute values for REGSET_TM_CGPR register set
(3) Renamed flush_tmreg_to_thread as flush_tmregs_to_thread
(4) Fixed 32 bit checkpointed GPR support
(5) Changed commit messages accordingly

Outstanding Issues
==================
(1) Running DSCR register value inside a transaction does not seem to be saved
    at thread.dscr when the process stops for ptrace examination.
    
Test programs
=============
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <linux/elf.h>
#include <linux/types.h>
#include <linux/ptrace.h>

typedef long long u64;
typedef unsigned int u32;
typedef __vector128 vector128;

/* TM CFPR */
struct tm_cfpr {
	u64	fpr[32];
	u64	fpscr;
};

/* TM CVMX */
struct tm_cvmx {
        vector128	vr[32] __attribute__((aligned(16)));
        vector128	vscr __attribute__((aligned(16)));
	u32		vrsave;	
};

/* TM SPR */
struct tm_spr_regs {
	u64	tm_tfhar;
	u64	tm_texasr;
	u64	tm_tfiar;
	u64	tm_orig_msr;
	u64	tm_tar;
	u64	tm_ppr;
	u64	tm_dscr;
};

/* Miscellaneous registers */
struct misc_regs {
	u64	dscr;
	u64	ppr;
	u64	tar;
};

/* TM instructions */
#define TBEGIN          ".long 0x7C00051D ;"
#define TEND            ".long 0x7C00055D ;"

/* SPR number */
#define SPRN_DSCR	0x3
#define SPRN_TAR	815

/* ELF core notes */
#define NT_PPC_TM_SPR  0x103           /* PowerPC transactional memory special registers */
#define NT_PPC_TM_CGPR 0x104           /* PowerpC transactional memory checkpointed GPR */
#define NT_PPC_TM_CFPR 0x105           /* PowerPC transactional memory checkpointed FPR */
#define NT_PPC_TM_CVMX 0x106           /* PowerPC transactional memory checkpointed VMX */
#define NT_PPC_MISC    0x107           /* PowerPC miscellaneous registers */

#define VAL1 1
#define VAL2 2
#define VAL3 3
#define VAL4 4

int main(int argc, char *argv[])
{
	struct tm_spr_regs *tmr1;
	struct pt_regs *pregs1, *pregs2;
	struct tm_cfpr *fpr, *fpr1;
	struct misc_regs *dbr1;
	struct iovec iov;

	pid_t child;
	int ret = 0, status = 0, i = 0, flag = 1;

	pregs2 = (struct pt_regs *) malloc(sizeof(struct pt_regs));
	fpr = (struct tm_cfpr *) malloc(sizeof(struct tm_cfpr));

	child = fork();
	if (child < 0) {
		printf("fork() failed \n");
		exit(-1);
	}

	/* Child code */
	if (child == 0) {
		asm __volatile__(
			"6: ;"			/* TM checkpointed values */
			"li 1, %[val1];"	/* GPR[1] */
			".long 0x7C210166;"	/* FPR[1] */
			"li 2, %[val2];"	/* GPR[2] */
			".long 0x7C420166;"	/* FPR[2] */
			"mtspr %[tar], 1;"	/* TAR */
 			"mtspr %[dscr], 2;"	/* DSCR */
			"1: ;"
			TBEGIN			/* TM running values */
			"beq 2f ;"
		 	"li 1, %[val3];"	/* GPR[1] */
                        ".long 0x7C210166;"	/* FPR[1] */
                        "li 2, %[val4];"	/* GPR[2] */
                        ".long 0x7C420166;"	/* FPR[2] */
                        "mtspr %[tar], 1;"	/* TAR */
			"mtspr %[dscr], 2;"	/* DSCR */
			"b .;"
			TEND
			"2: ;"			/* Abort handler */
			"b 1b;"			/* Start from TBEGIN */

			"3: ;"
			"b 6b;"			/* Start all over again */
			:: [dscr]"i"(SPRN_DSCR), [tar]"i"(SPRN_TAR), [val1]"i"(VAL1), [val2]"i"(VAL2), [val3]"i"(VAL3), [val4]"i"(VAL4)
			: "memory", "r7");
	}

	/* Parent */
	if (child) {
		do {
			memset(pregs2, 0 , sizeof(struct pt_regs));
			memset(fpr, 0 , sizeof(struct tm_cfpr));

			/* Wait till child hits "b ." instruction */
			sleep(3);

			/* Attach tracee */
			ret = ptrace(PTRACE_ATTACH, child, NULL, NULL);
			if (ret == -1) {
				printf("PTRACE_ATTACH failed: %s\n", strerror(errno));
				exit(-1);
			}

			ret = waitpid(child, NULL, 0);
			if (ret != child) {
				printf("PID does not match\n");
				exit(-1);
			}

			/* TM specific SPR */
			iov.iov_base = (struct tm_spr_regs *) malloc(sizeof(struct tm_spr_regs));
			iov.iov_len = sizeof(struct tm_spr_regs);
			ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_SPR, &iov);
			if (ret == -1) {
				printf("PTRACE_GETREGSET: NT_PPC_TM_SPR failed %s\n", strerror(errno));
				exit(-1);
			}

			if (iov.iov_len != sizeof(struct tm_spr_regs)) {
				printf("NT_PPC_TM_SPR: Length returned is wrong\n");
				exit(-1);
			}

			tmr1 = iov.iov_base;
			printf("-------TM specific SPR------\n");
			printf("TM TFHAR: %llx\n", tmr1->tm_tfhar);
			printf("TM TEXASR: %llx\n", tmr1->tm_texasr);
			printf("TM TFIAR: %llx\n", tmr1->tm_tfiar);
			printf("TM CH ORIG_MSR: %llx\n", tmr1->tm_orig_msr);
			printf("TM CH TAR: %llx\n", tmr1->tm_tar);
			printf("TM CH PPR: %llx\n", tmr1->tm_ppr);
			printf("TM CH DSCR: %llx\n", tmr1->tm_dscr);

			if (tmr1->tm_tar == VAL1)
				printf("TAR PASSED\n");
			else
				printf("TAR FAILED\n");

			if (tmr1->tm_dscr == VAL2)
				printf("DSCR PASSED\n");
			else
				printf("DSCR FAILED\n");

			/* TM checkpointed GPR */
			iov.iov_base = (struct pt_regs *) malloc(sizeof(struct pt_regs));;
			iov.iov_len = sizeof(struct pt_regs);
			ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov);
			if (ret == -1) {
				printf("PTRACE_GETREGSET: NT_PPC_TM_CGPR failed: %s\n", strerror(errno));
				exit(-1);
			}

			if (iov.iov_len != sizeof(struct pt_regs)) {
				printf("NT_PPC_TM_CGPR: Length returned is wrong\n");
				exit(-1);
			}

			pregs1 = iov.iov_base;
			printf("-------TM checkpointed GPR-----\n");
			printf("TM CH GPR[1]: %x\n", pregs1->gpr[1]);
			printf("TM CH GPR[2]: %x\n", pregs1->gpr[2]);
			printf("TM CH NIP: %x\n", pregs1->nip);
			printf("TM CH LINK: %x\n", pregs1->link);
			printf("TM CH CCR: %x\n", pregs1->ccr);

			if (pregs1->gpr[1] == VAL1)
				printf("GPR[1] PASSED\n");
			else
				printf("GPR[1] FAILED\n");

			if (pregs1->gpr[2] == VAL2)
				printf("GPR[2] PASSED\n");
			else
				printf("GPR[2] FAILED\n");

			/* TM running GPR */
			ret = ptrace(PTRACE_GETREGS, child, NULL, pregs2);
			if (ret == -1) {
				printf("PTRACE_GETREGS fail: %s\n", strerror(errno));
				exit(-1);
			}

			printf("-------TM running GPR-----\n");
			printf("TM RN GPR[1]: %x\n", pregs2->gpr[1]);
			printf("TM RN GPR[2]: %x\n", pregs2->gpr[2]);
			printf("TM RN NIP: %x\n", pregs2->nip);
			printf("TM RN LINK: %x\n", pregs2->link);
			printf("TM RN CCR: %x\n", pregs2->ccr);

			
			if (pregs2->gpr[1] == VAL3)
				printf("GPR[1] PASSED\n");
			else
				printf("GPR[1] FAILED\n");

			if (pregs2->gpr[2] == VAL4)
				printf("GPR[2] PASSED\n");
			else
				printf("GPR[2] FAILED\n");

			/* TM checkpointed FPR */
			iov.iov_base = (struct tm_cfpr *) malloc(sizeof(struct tm_cfpr));;
			iov.iov_len = sizeof(struct tm_cfpr);
			ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov);
			if (ret == -1) {
				printf("PTRACE_GETREGSET: NT_PPC_TM_CFPR: Failed: %s\n", strerror(errno));
				exit(-1);
			}

			if (iov.iov_len != sizeof(struct tm_cfpr)) {
				printf("NT_PPC_TM_CFPR: Length returned is wrong\n");
				exit(-1);
			}

			fpr1 = iov.iov_base;
			printf("-------TM checkpointed FPR-----\n");
			printf("TM CH FPR[1]: %llx\n", fpr1->fpr[1]);
			printf("TM CH FPR[2]: %llx\n", fpr1->fpr[2]);
			printf("TM CH FPSCR: %llx\n", fpr1->fpscr);

			if (fpr1->fpr[1] == VAL1)
				printf("FPR[1] PASSED\n");
			else
				printf("FPR[1] FAILED\n");

			if (fpr1->fpr[2] == VAL2)
				printf("FPR[2] PASSED\n");
			else
				printf("FPR[2] FAILED\n");

			/* TM running FPR */
			ret = ptrace(PTRACE_GETFPREGS, child, NULL, fpr);
			if (ret == -1) {
				printf("PTRACE_GETFPREGS failed: %s\n", strerror(errno));
				exit(-1);
			}

			printf("-------TM running FPR-----\n");
			printf("TM RN FPR[1]: %llx\n", fpr->fpr[1]);
			printf("TM RN FPR[2]: %llx\n", fpr->fpr[2]);
			printf("TM RN FPSCR: %llx\n", fpr->fpscr);

			if (fpr->fpr[1] == VAL3)
				printf("FPR[1] PASSED\n");
			else
				printf("FPR[1] FAILED\n");

			if (fpr->fpr[2] == VAL4)
				printf("FPR[2] PASSED\n");
			else
				printf("FPR[2] FAILED\n");

			/* Misc registers */
			iov.iov_base = (struct misc_regs *) malloc(sizeof(struct misc_regs));
			iov.iov_len = sizeof(struct misc_regs);
			ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_MISC, &iov);
			if (ret == -1) {
				printf("PTRACE_GETREGSET: NT_PPC_MISC: Failed: %s\n", strerror(errno));
				exit(-1);
			}

			if (iov.iov_len != sizeof(struct misc_regs)) {
				printf("NT_PPC_TM_MISC: Length returned is wrong\n");
				exit(-1);
			}

			dbr1  = iov.iov_base;
			printf("-------Running miscellaneous registers-------\n");
			printf("TM RN DSCR: %llx\n", dbr1->dscr);
			printf("TM RN PPR: %llx\n", dbr1->ppr);
			printf("TM RN TAR: %llx\n", dbr1->tar);

			if (dbr1->tar == VAL3)
				printf("TAR PASSED\n");
			else
				printf("TAR FAILED\n");

			if (dbr1->dscr == VAL4)
				printf("DSCR PASSED\n");
			else
				printf("DSCR FAILED\n");

			/* Detach tracee */
			ret = ptrace(PTRACE_DETACH, child, NULL, NULL);
			if (ret == -1) {
				printf("PTRACE_DETACH failed: %s\n", strerror(errno));
				exit(-1);
			}
		} while (0);
	}
	return 0;
}

Test Results
============
(1) 64 bit application ==>

-------TM specific SPR------
TM TFHAR: 10000960
TM TEXASR: de000001ac000001
TM TFIAR: c0000000000465f6
TM CH ORIG_MSR: 900000050000f032
TM CH TAR: 1
TM CH PPR: c000000000000
TM CH DSCR: 2
TAR PASSED
DSCR PASSED
-------TM checkpointed GPR-----
TM CH GPR[1]: 1
TM CH GPR[2]: 2
TM CH NIP: 10000960
TM CH LINK: 10000904
TM CH CCR: 22000422
GPR[1] PASSED
GPR[2] PASSED
-------TM running GPR-----
TM RN GPR[1]: 3
TM RN GPR[2]: 4
TM RN NIP: 1000097c
TM RN LINK: 10000904
TM RN CCR: 2000422
GPR[1] PASSED
GPR[2] PASSED
-------TM checkpointed FPR-----
TM CH FPR[1]: 1
TM CH FPR[2]: 2
TM CH FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------TM running FPR-----
TM RN FPR[1]: 3
TM RN FPR[2]: 4
TM RN FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------Running miscellaneous registers-------
TM RN DSCR: 0
TM RN PPR: c000000000000
TM RN TAR: 3
TAR PASSED
DSCR FAILED

(2) 32 bit application ==>

-------TM specific SPR------
TM TFHAR: 100006b8
TM TEXASR: de000001ac000001
TM TFIAR: c0000000000465f6
TM CH ORIG_MSR: 100000050000f032
TM CH TAR: 1
TM CH PPR: c000000000000
TM CH DSCR: 2
TAR PASSED
DSCR PASSED
-------TM checkpointed GPR-----
TM CH GPR[1]: 1
TM CH GPR[2]: 2
TM CH NIP: 100006b8
TM CH LINK: 1000066c
TM CH CCR: 22000422
GPR[1] PASSED
GPR[2] PASSED
-------TM running GPR-----
TM RN GPR[1]: 3
TM RN GPR[2]: 4
TM RN NIP: 100006d4
TM RN LINK: 1000066c
TM RN CCR: 2000422
GPR[1] PASSED
GPR[2] PASSED
-------TM checkpointed FPR-----
TM CH FPR[1]: 1
TM CH FPR[2]: 2
TM CH FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------TM running FPR-----
TM RN FPR[1]: 3
TM RN FPR[2]: 4
TM RN FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------Running miscellaneous registers-------
TM RN DSCR: 0
TM RN PPR: c000000000000
TM RN TAR: 3
TAR PASSED
DSCR FAILED


Anshuman Khandual (3):
  elf: Add some new PowerPC specifc note sections
  powerpc, ptrace: Enable support for transactional memory register sets
  powerpc, ptrace: Enable support for miscellaneous registers

 arch/powerpc/include/asm/switch_to.h |   8 +
 arch/powerpc/kernel/process.c        |  24 +
 arch/powerpc/kernel/ptrace.c         | 873 +++++++++++++++++++++++++++++++++--
 include/uapi/linux/elf.h             |   5 +
 4 files changed, 881 insertions(+), 29 deletions(-)

-- 
1.7.11.7

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH V3 1/3] elf: Add some new PowerPC specifc note sections
  2014-05-23 15:15 [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
@ 2014-05-23 15:15 ` Anshuman Khandual
  2014-05-23 15:15 ` [PATCH V3 2/3] powerpc, ptrace: Enable support for transactional memory register sets Anshuman Khandual
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 19+ messages in thread
From: Anshuman Khandual @ 2014-05-23 15:15 UTC (permalink / raw)
  To: linux-kernel, linuxppc-dev, peterz, akpm, tglx
  Cc: mikey, james.hogan, avagin, Paul.Clothier, palves, oleg,
	dhowells, davej, davem

This patch adds four new note sections for transactional memory
and one note section for some miscellaneous registers. This addition
of new elf note sections extends the existing elf ABI without affecting
it in any manner.

Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
 include/uapi/linux/elf.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index ef6103b..4040124 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -379,6 +379,11 @@ typedef struct elf64_shdr {
 #define NT_PPC_VMX	0x100		/* PowerPC Altivec/VMX registers */
 #define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
 #define NT_PPC_VSX	0x102		/* PowerPC VSX registers */
+#define NT_PPC_TM_SPR	0x103		/* PowerPC TM special registers */
+#define NT_PPC_TM_CGPR	0x104		/* PowerpC TM checkpointed GPR */
+#define NT_PPC_TM_CFPR	0x105		/* PowerPC TM checkpointed FPR */
+#define NT_PPC_TM_CVMX	0x106		/* PowerPC TM checkpointed VMX */
+#define NT_PPC_MISC	0x107		/* PowerPC miscellaneous registers */
 #define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */
 #define NT_386_IOPERM	0x201		/* x86 io permission bitmap (1=deny) */
 #define NT_X86_XSTATE	0x202		/* x86 extended state using xsave */
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH V3 2/3] powerpc, ptrace: Enable support for transactional memory register sets
  2014-05-23 15:15 [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
  2014-05-23 15:15 ` [PATCH V3 1/3] elf: Add some new PowerPC specifc note sections Anshuman Khandual
@ 2014-05-23 15:15 ` Anshuman Khandual
  2014-07-24  6:56   ` Sam Bobroff
  2014-08-27 21:35   ` Sukadev Bhattiprolu
  2014-05-23 15:15 ` [PATCH V3 3/3] powerpc, ptrace: Enable support for miscellaneous registers Anshuman Khandual
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 19+ messages in thread
From: Anshuman Khandual @ 2014-05-23 15:15 UTC (permalink / raw)
  To: linux-kernel, linuxppc-dev, peterz, akpm, tglx
  Cc: mikey, james.hogan, avagin, Paul.Clothier, palves, oleg,
	dhowells, davej, davem

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@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/switch_to.h |   8 +
 arch/powerpc/kernel/process.c        |  24 ++
 arch/powerpc/kernel/ptrace.c         | 792 +++++++++++++++++++++++++++++++++--
 3 files changed, 795 insertions(+), 29 deletions(-)

diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index 0e83e7d..2737f46 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -80,6 +80,14 @@ static inline void flush_spe_to_thread(struct task_struct *t)
 }
 #endif
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+extern void flush_tmregs_to_thread(struct task_struct *);
+#else
+static inline void flush_tmregs_to_thread(struct task_struct *t)
+{
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
 static inline void clear_task_ebb(struct task_struct *t)
 {
 #ifdef CONFIG_PPC_BOOK3S_64
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 31d0215..e247898 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -695,6 +695,30 @@ static inline void __switch_to_tm(struct task_struct *prev)
 	}
 }
 
+void flush_tmregs_to_thread(struct task_struct *tsk)
+{
+	/*
+	 * If task is not current, it should have been flushed
+	 * already to it's thread_struct during __switch_to().
+	 */
+	if (tsk != current)
+		return;
+
+	preempt_disable();
+	if (tsk->thread.regs) {
+		/*
+		 * If we are still current, the TM state need to
+		 * be flushed to thread_struct as it will be still
+		 * present in the current cpu.
+		 */
+		if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
+			__switch_to_tm(tsk);
+			tm_recheckpoint_new_task(tsk);
+		}
+	}
+	preempt_enable();
+}
+
 /*
  * This is called if we are on the way out to userspace and the
  * TIF_RESTORE_TM flag is set.  It checks if we need to reload
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 2e3d2bf..17642ef 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -357,6 +357,17 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
 	return ret;
 }
 
+/*
+ * When any transaction is active, "thread_struct->transact_fp" holds
+ * the current running value of all FPR registers and "thread_struct->
+ * fp_state" holds the last checkpointed FPR registers state for the
+ * current transaction.
+ *
+ * struct data {
+ * 	u64	fpr[32];
+ * 	u64	fpscr;
+ * };
+ */
 static int fpr_get(struct task_struct *target, const struct user_regset *regset,
 		   unsigned int pos, unsigned int count,
 		   void *kbuf, void __user *ubuf)
@@ -365,21 +376,41 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
 	u64 buf[33];
 	int i;
 #endif
-	flush_fp_to_thread(target);
+	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+		flush_fp_to_thread(target);
+		flush_altivec_to_thread(target);
+		flush_tmregs_to_thread(target);
+	} else {
+		flush_fp_to_thread(target);
+	}
 
 #ifdef CONFIG_VSX
 	/* 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;
+	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+		for (i = 0; i < 32 ; i++)
+			buf[i] = target->thread.TS_TRANS_FPR(i);
+		buf[32] = target->thread.transact_fp.fpscr;
+	} else {
+		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);
 
 #else
-	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
-		     offsetof(struct thread_fp_state, fpr[32][0]));
+	if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
+		BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
+				offsetof(struct transact_fp, fpr[32][0]));
 
-	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				   &target->thread.transact_fp, 0, -1);
+	} esle {
+		BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+			     offsetof(struct thread_fp_state, fpr[32][0]));
+
+		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 				   &target->thread.fp_state, 0, -1);
+	}
 #endif
 }
 
@@ -391,23 +422,44 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
 	u64 buf[33];
 	int i;
 #endif
-	flush_fp_to_thread(target);
+	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+		flush_fp_to_thread(target);
+		flush_altivec_to_thread(target);
+		flush_tmregs_to_thread(target);
+	} else {
+		flush_fp_to_thread(target);
+	}
 
 #ifdef CONFIG_VSX
 	/* 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];
+	for (i = 0; i < 32 ; i++) {
+		if (MSR_TM_ACTIVE(target->thread.regs->msr))
+			target->thread.TS_TRANS_FPR(i) = buf[i];
+		else
+			target->thread.TS_FPR(i) = buf[i];
+	}
+	if (MSR_TM_ACTIVE(target->thread.regs->msr))
+		target->thread.transact_fp.fpscr = buf[32];
+	else
+		target->thread.fp_state.fpscr = buf[32];
 	return 0;
 #else
-	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
-		     offsetof(struct thread_fp_state, fpr[32][0]));
+	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+		BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
+			     offsetof(struct transact_fp, fpr[32][0]));
 
-	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-				  &target->thread.fp_state, 0, -1);
+		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					  &target->thread.transact_fp, 0, -1);
+	} else {
+		BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+			     offsetof(struct thread_fp_state, fpr[32][0]));
+
+		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				&target->thread.fp_state, 0, -1);
+	}
 #endif
 }
 
@@ -432,20 +484,44 @@ static int vr_active(struct task_struct *target,
 	return target->thread.used_vr ? regset->n : 0;
 }
 
+/*
+ * When any transaction is active, "thread_struct->transact_vr" holds
+ * the current running value of all VMX registers and "thread_struct->
+ * vr_state" holds the last checkpointed value of VMX registers for the
+ * current transaction.
+ *
+ * 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)
 {
 	int ret;
+	struct thread_vr_state *addr;
 
-	flush_altivec_to_thread(target);
+	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+		flush_fp_to_thread(target);
+		flush_altivec_to_thread(target);
+		flush_tmregs_to_thread(target);
+	} else {
+		flush_altivec_to_thread(target);
+	}
 
 	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
 		     offsetof(struct thread_vr_state, vr[32]));
 
+	if (MSR_TM_ACTIVE(target->thread.regs->msr))
+		addr = &target->thread.transact_vr;
+	else
+		addr = &target->thread.vr_state;
+
 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-				  &target->thread.vr_state, 0,
-				  33 * sizeof(vector128));
+				addr, 0, 33 * sizeof(vector128));
+
 	if (!ret) {
 		/*
 		 * Copy out only the low-order word of vrsave.
@@ -455,11 +531,14 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
 			u32 word;
 		} vrsave;
 		memset(&vrsave, 0, sizeof(vrsave));
-		vrsave.word = target->thread.vrsave;
+		if (MSR_TM_ACTIVE(target->thread.regs->msr))
+			vrsave.word = target->thread.transact_vrsave;
+		else
+			vrsave.word = target->thread.vrsave;
+
 		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
 					  33 * sizeof(vector128), -1);
 	}
-
 	return ret;
 }
 
@@ -467,16 +546,27 @@ 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)
 {
+	struct thread_vr_state *addr;
 	int ret;
 
-	flush_altivec_to_thread(target);
+	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+		flush_fp_to_thread(target);
+		flush_altivec_to_thread(target);
+		flush_tmregs_to_thread(target);
+	} else {
+		flush_altivec_to_thread(target);
+	}
 
 	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
 		     offsetof(struct thread_vr_state, vr[32]));
 
+	if (MSR_TM_ACTIVE(target->thread.regs->msr))
+		addr = &target->thread.transact_vr;
+	else
+		addr = &target->thread.vr_state;
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-				 &target->thread.vr_state, 0,
-				 33 * sizeof(vector128));
+			addr, 0, 33 * sizeof(vector128));
+
 	if (!ret && count > 0) {
 		/*
 		 * We use only the first word of vrsave.
@@ -486,13 +576,21 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
 			u32 word;
 		} vrsave;
 		memset(&vrsave, 0, sizeof(vrsave));
-		vrsave.word = target->thread.vrsave;
+
+		if (MSR_TM_ACTIVE(target->thread.regs->msr))
+			vrsave.word = target->thread.transact_vrsave;
+		else
+			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;
+		if (!ret) {
+			if (MSR_TM_ACTIVE(target->thread.regs->msr))
+				target->thread.transact_vrsave = vrsave.word;
+			else
+				target->thread.vrsave = vrsave.word;
+		}
 	}
-
 	return ret;
 }
 #endif /* CONFIG_ALTIVEC */
@@ -613,6 +711,442 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
 }
 #endif /* CONFIG_SPE */
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+
+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;
+}
+/*
+ *  Transactional memory SPR
+ *
+ * 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;
+
+	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);
+
+	/* TFHAR register */
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+			&target->thread.tm_tfhar, 0, sizeof(u64));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar) +
+			sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
+
+	/* TEXASR register */
+	if (!ret)
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+			&target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr) +
+			sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
+
+	/* TFIAR register */
+	if (!ret)
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+			&target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar) +
+			sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
+
+	/* 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));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr) +
+			sizeof(unsigned long) + sizeof(struct pt_regs)
+				!= offsetof(struct thread_struct, tm_tar));
+
+	/* 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));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
+			+ sizeof(unsigned long) !=
+				offsetof(struct thread_struct, tm_ppr));
+
+	/* 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));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
+			sizeof(unsigned long) !=
+				offsetof(struct thread_struct, tm_dscr));
+
+	/* 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;
+}
+
+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;
+
+	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);
+
+	/* TFHAR register */
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				&target->thread.tm_tfhar, 0, sizeof(u64));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar)
+		+ sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
+
+	/* TEXASR register */
+	if (!ret)
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+			&target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr)
+		+ sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
+
+	/* TFIAR register */
+	if (!ret)
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+			&target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar)
+		+ sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
+
+	/* 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));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr)
+		+ sizeof(unsigned long) + sizeof(struct pt_regs) !=
+			offsetof(struct thread_struct, tm_tar));
+
+	/* 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));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
+			+ sizeof(unsigned long) != offsetof(struct thread_struct, tm_ppr));
+
+	/* 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));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
+			sizeof(unsigned long) !=
+				offsetof(struct thread_struct, tm_dscr));
+
+	/* 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;
+}
+
+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 Checkpointed GPR
+ *
+ * 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;
+}
+
+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;
+}
+
+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 Checkpointed FPR
+ *
+ * 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)
+{
+#ifdef CONFIG_VSX
+	u64 buf[33];
+	int i;
+#endif
+	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);
+
+#ifdef CONFIG_VSX
+	/* 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);
+
+#else
+	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+		offsetof(struct thread_fp_state, fpr[32][0]));
+
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+			&target->thread.thread_fp_state, 0, -1);
+#endif
+}
+
+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)
+{
+#ifdef CONFIG_VSX
+	u64 buf[33];
+	int i;
+#endif
+	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);
+
+#ifdef CONFIG_VSX
+	/* 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;
+#else
+	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+		      offsetof(struct thread_fp_state, fpr[32][0]));
+
+	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				&target->thread.fp_state, 0, -1);
+#endif
+}
+
+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 Checkpointed VMX
+ *
+ * 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;
+
+	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);
+
+	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
+		     offsetof(struct thread_vr_state, vr[32]));
+
+	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;
+}
+
+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;
+
+	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);
+
+	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
+		offsetof(struct thread_vr_state, vr[32]));
+
+	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.
+		 */
+		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.
@@ -629,6 +1163,12 @@ enum powerpc_regset {
 #ifdef CONFIG_SPE
 	REGSET_SPE,
 #endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+	REGSET_TM_SPR,		/* TM specific SPR */
+	REGSET_TM_CGPR,		/* TM checkpointed GPR */
+	REGSET_TM_CFPR,		/* TM checkpointed FPR */
+	REGSET_TM_CVMX,		/* TM checkpointed VMX */
+#endif
 };
 
 static const struct user_regset native_regsets[] = {
@@ -663,6 +1203,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 = 7,
+		.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 = 34,
+		.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 = {
@@ -690,7 +1252,7 @@ static int gpr32_get(struct task_struct *target,
 	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; 
+			target->thread.regs->gpr[i] = NV_REG_POISON;
 	}
 
 	pos /= sizeof(reg);
@@ -803,6 +1365,157 @@ static int gpr32_set(struct task_struct *target,
 					 (PT_TRAP + 1) * sizeof(reg), -1);
 }
 
+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)
+{
+	const unsigned long *regs = &target->thread.ckpt_regs.gpr[0];
+	compat_ulong_t *k = kbuf;
+	compat_ulong_t __user *u = ubuf;
+	compat_ulong_t reg;
+	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);
+
+	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);
+	count /= sizeof(reg);
+
+	if (kbuf)
+		for (; count > 0 && pos < PT_MSR; --count)
+			*k++ = regs[pos++];
+	else
+		for (; count > 0 && pos < PT_MSR; --count)
+			if (__put_user((compat_ulong_t) regs[pos++], u++))
+				return -EFAULT;
+
+	if (count > 0 && pos == PT_MSR) {
+		reg = get_user_msr(target);
+		if (kbuf)
+			*k++ = reg;
+		else if (__put_user(reg, u++))
+			return -EFAULT;
+		++pos;
+		--count;
+	}
+
+	if (kbuf)
+		for (; count > 0 && pos < PT_REGS_COUNT; --count)
+			*k++ = regs[pos++];
+	else
+		for (; count > 0 && pos < PT_REGS_COUNT; --count)
+			if (__put_user((compat_ulong_t) regs[pos++], u++))
+				return -EFAULT;
+
+	kbuf = k;
+	ubuf = u;
+	pos *= sizeof(reg);
+	count *= sizeof(reg);
+	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+					PT_REGS_COUNT * sizeof(reg), -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)
+{
+	unsigned long *regs = &target->thread.ckpt_regs.gpr[0];
+	const compat_ulong_t *k = kbuf;
+	const compat_ulong_t __user *u = ubuf;
+	compat_ulong_t reg;
+
+	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);
+
+	if (target->thread.regs == NULL)
+		return -EIO;
+
+	CHECK_FULL_REGS(target->thread.regs);
+
+	pos /= sizeof(reg);
+	count /= sizeof(reg);
+
+	if (kbuf)
+		for (; count > 0 && pos < PT_MSR; --count)
+			regs[pos++] = *k++;
+	else
+		for (; count > 0 && pos < PT_MSR; --count) {
+			if (__get_user(reg, u++))
+				return -EFAULT;
+			regs[pos++] = reg;
+		}
+
+
+	if (count > 0 && pos == PT_MSR) {
+		if (kbuf)
+			reg = *k++;
+		else if (__get_user(reg, u++))
+			return -EFAULT;
+		set_user_msr(target, reg);
+		++pos;
+		--count;
+	}
+
+	if (kbuf) {
+		for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
+			regs[pos++] = *k++;
+		for (; count > 0 && pos < PT_TRAP; --count, ++pos)
+			++k;
+	} else {
+		for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
+			if (__get_user(reg, u++))
+				return -EFAULT;
+			regs[pos++] = reg;
+		}
+		for (; count > 0 && pos < PT_TRAP; --count, ++pos)
+			if (__get_user(reg, u++))
+				return -EFAULT;
+	}
+
+	if (count > 0 && pos == PT_TRAP) {
+		if (kbuf)
+			reg = *k++;
+		else if (__get_user(reg, u++))
+			return -EFAULT;
+		set_user_trap(target, reg);
+		++pos;
+		--count;
+	}
+
+	kbuf = k;
+	ubuf = u;
+	pos *= sizeof(reg);
+	count *= sizeof(reg);
+	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+					 (PT_TRAP + 1) * sizeof(reg), -1);
+}
+
+
 /*
  * These are the regset flavors matching the CONFIG_PPC32 native set.
  */
@@ -831,6 +1544,28 @@ 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 = 7,
+		.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 = 34,
+		.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 = {
@@ -1754,7 +2489,6 @@ long arch_ptrace(struct task_struct *child, long request,
 					     REGSET_SPE, 0, 35 * sizeof(u32),
 					     datavp);
 #endif
-
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH V3 3/3] powerpc, ptrace: Enable support for miscellaneous registers
  2014-05-23 15:15 [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
  2014-05-23 15:15 ` [PATCH V3 1/3] elf: Add some new PowerPC specifc note sections Anshuman Khandual
  2014-05-23 15:15 ` [PATCH V3 2/3] powerpc, ptrace: Enable support for transactional memory register sets Anshuman Khandual
@ 2014-05-23 15:15 ` Anshuman Khandual
  2014-08-27 21:35   ` Sukadev Bhattiprolu
  2014-06-12  9:09 ` [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 19+ messages in thread
From: Anshuman Khandual @ 2014-05-23 15:15 UTC (permalink / raw)
  To: linux-kernel, linuxppc-dev, peterz, akpm, tglx
  Cc: mikey, james.hogan, avagin, Paul.Clothier, palves, oleg,
	dhowells, davej, davem

This patch enables get and set of miscellaneous registers through ptrace
PTRACE_GETREGSET/PTRACE_SETREGSET interface by implementing new powerpc
specific register set REGSET_MISC support corresponding to the new ELF
core note NT_PPC_MISC added previously in this regard.

Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
 arch/powerpc/kernel/ptrace.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 17642ef..63b883a 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1149,6 +1149,76 @@ static int tm_cvmx_set(struct task_struct *target, const struct user_regset *reg
 #endif	/* CONFIG_PPC_TRANSACTIONAL_MEM */
 
 /*
+ * Miscellaneous Registers
+ *
+ * struct {
+ * 	unsigned long dscr;
+ *	unsigned long ppr;
+ * 	unsigned long tar;
+ * };
+ */
+static int misc_get(struct task_struct *target, const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   void *kbuf, void __user *ubuf)
+{
+	int ret;
+
+	/* DSCR register */
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					&target->thread.dscr, 0,
+					sizeof(unsigned long));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned long) +
+				sizeof(unsigned long) != offsetof(struct thread_struct, ppr));
+
+	/* PPR register */
+	if (!ret)
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					  &target->thread.ppr, sizeof(unsigned long),
+					  2 * sizeof(unsigned long));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
+						!= offsetof(struct thread_struct, tar));
+	/* TAR register */
+	if (!ret)
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					  &target->thread.tar, 2 * sizeof(unsigned long),
+					  3 * sizeof(unsigned long));
+	return ret;
+}
+
+static int misc_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;
+
+	/* DSCR register */
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					&target->thread.dscr, 0,
+					sizeof(unsigned long));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned long) +
+			sizeof(unsigned long) != offsetof(struct thread_struct, ppr));
+
+	/* PPR register */
+	if (!ret)
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+						&target->thread.ppr, sizeof(unsigned long),
+						2 * sizeof(unsigned long));
+
+	BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
+						!= offsetof(struct thread_struct, tar));
+
+	/* TAR register */
+	if (!ret)
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+						&target->thread.tar, 2 * sizeof(unsigned long),
+						3 * sizeof(unsigned long));
+	return ret;
+}
+
+/*
  * These are our native regset flavors.
  */
 enum powerpc_regset {
@@ -1169,6 +1239,7 @@ enum powerpc_regset {
 	REGSET_TM_CFPR,		/* TM checkpointed FPR */
 	REGSET_TM_CVMX,		/* TM checkpointed VMX */
 #endif
+	REGSET_MISC		/* Miscellaneous */
 };
 
 static const struct user_regset native_regsets[] = {
@@ -1225,6 +1296,11 @@ static const struct user_regset native_regsets[] = {
 		.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
 	},
 #endif
+	[REGSET_MISC] = {
+		.core_note_type = NT_PPC_MISC, .n = 3,
+		.size = sizeof(u64), .align = sizeof(u64),
+		.get = misc_get, .set = misc_set
+	},
 };
 
 static const struct user_regset_view user_ppc_native_view = {
@@ -1566,6 +1642,11 @@ static const struct user_regset compat_regsets[] = {
 		.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
 	},
 #endif
+	[REGSET_MISC] = {
+		.core_note_type = NT_PPC_MISC, .n = 3,
+		.size = sizeof(u64), .align = sizeof(u64),
+		.get = misc_get, .set = misc_set
+	},
 };
 
 static const struct user_regset_view user_ppc_compat_view = {
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
  2014-05-23 15:15 [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
                   ` (2 preceding siblings ...)
  2014-05-23 15:15 ` [PATCH V3 3/3] powerpc, ptrace: Enable support for miscellaneous registers Anshuman Khandual
@ 2014-06-12  9:09 ` Anshuman Khandual
  2014-07-17 10:27   ` Anshuman Khandual
  2014-07-24  6:52 ` Sam Bobroff
  2014-09-11  6:14 ` Anshuman Khandual
  5 siblings, 1 reply; 19+ messages in thread
From: Anshuman Khandual @ 2014-06-12  9:09 UTC (permalink / raw)
  To: Anshuman Khandual, Benjamin Herrenschmidt
  Cc: Michael Neuling, james.hogan, avagin, Paul.Clothier, davem,
	peterz, palves, linux-kernel, oleg, dhowells, linuxppc-dev,
	davej, akpm, tglx

On 05/23/2014 08:45 PM, Anshuman Khandual wrote:
> 	This patch series adds five new ELF core note sections which can be
> used with existing ptrace request PTRACE_GETREGSET/SETREGSET for accessing
> various transactional memory and miscellaneous register sets on PowerPC
> platform. Please find a test program exploiting these new ELF core note
> types on a POWER8 system.
> 
> RFC: https://lkml.org/lkml/2014/4/1/292
> V1:  https://lkml.org/lkml/2014/4/2/43
> V2:  https://lkml.org/lkml/2014/5/5/88
> 
> Changes in V3
> =============
> (1) Added two new error paths in every TM related get/set functions when regset
>     support is not present on the system (ENODEV) or when the process does not
>     have any transaction active (ENODATA) in the context
> 
> (2) Installed the active hooks for all the newly added regset core note types
> 
> Changes in V2
> =============
> (1) Removed all the power specific ptrace requests corresponding to new NT_PPC_*
>     elf core note types. Now all the register sets can be accessed from ptrace
>     through PTRACE_GETREGSET/PTRACE_SETREGSET using the individual NT_PPC* core
>     note type instead
> (2) Fixed couple of attribute values for REGSET_TM_CGPR register set
> (3) Renamed flush_tmreg_to_thread as flush_tmregs_to_thread
> (4) Fixed 32 bit checkpointed GPR support
> (5) Changed commit messages accordingly
> 
> Outstanding Issues
> ==================
> (1) Running DSCR register value inside a transaction does not seem to be saved
>     at thread.dscr when the process stops for ptrace examination.

Hey Ben,

Any updates on this patch series ?

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
  2014-06-12  9:09 ` [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
@ 2014-07-17 10:27   ` Anshuman Khandual
  2014-07-17 11:09     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 19+ messages in thread
From: Anshuman Khandual @ 2014-07-17 10:27 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Michael Neuling, james.hogan, avagin, Paul.Clothier, peterz,
	palves, linux-kernel, oleg, dhowells, linuxppc-dev, tglx, davej,
	akpm, davem

On 06/12/2014 02:39 PM, Anshuman Khandual wrote:
> On 05/23/2014 08:45 PM, Anshuman Khandual wrote:
>> 	This patch series adds five new ELF core note sections which can be
>> used with existing ptrace request PTRACE_GETREGSET/SETREGSET for accessing
>> various transactional memory and miscellaneous register sets on PowerPC
>> platform. Please find a test program exploiting these new ELF core note
>> types on a POWER8 system.
>>
>> RFC: https://lkml.org/lkml/2014/4/1/292
>> V1:  https://lkml.org/lkml/2014/4/2/43
>> V2:  https://lkml.org/lkml/2014/5/5/88
>>
>> Changes in V3
>> =============
>> (1) Added two new error paths in every TM related get/set functions when regset
>>     support is not present on the system (ENODEV) or when the process does not
>>     have any transaction active (ENODATA) in the context
>>
>> (2) Installed the active hooks for all the newly added regset core note types
>>
>> Changes in V2
>> =============
>> (1) Removed all the power specific ptrace requests corresponding to new NT_PPC_*
>>     elf core note types. Now all the register sets can be accessed from ptrace
>>     through PTRACE_GETREGSET/PTRACE_SETREGSET using the individual NT_PPC* core
>>     note type instead
>> (2) Fixed couple of attribute values for REGSET_TM_CGPR register set
>> (3) Renamed flush_tmreg_to_thread as flush_tmregs_to_thread
>> (4) Fixed 32 bit checkpointed GPR support
>> (5) Changed commit messages accordingly
>>
>> Outstanding Issues
>> ==================
>> (1) Running DSCR register value inside a transaction does not seem to be saved
>>     at thread.dscr when the process stops for ptrace examination.
> 
> Hey Ben,
> 
> Any updates on this patch series ?

Ben,

Any updates on this patch series ?

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
  2014-07-17 10:27   ` Anshuman Khandual
@ 2014-07-17 11:09     ` Benjamin Herrenschmidt
  2014-07-17 11:14       ` Michael Neuling
  0 siblings, 1 reply; 19+ messages in thread
From: Benjamin Herrenschmidt @ 2014-07-17 11:09 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: Michael Neuling, james.hogan, avagin, Paul.Clothier, peterz,
	palves, linux-kernel, oleg, dhowells, linuxppc-dev, tglx, davej,
	akpm, davem

> >
> >> Outstanding Issues
> >> ==================
> >> (1) Running DSCR register value inside a transaction does not seem to be saved
> >>     at thread.dscr when the process stops for ptrace examination.
> > 
> > Hey Ben,
> > 
> > Any updates on this patch series ?
> 
> Ben,
> 
> Any updates on this patch series ?

I haven't had a chance to review yet, I was hoping somebody else would..

Have you made any progress vs. the DSCR outstanding issue mentioned
above ?

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
  2014-07-17 11:09     ` Benjamin Herrenschmidt
@ 2014-07-17 11:14       ` Michael Neuling
  2014-07-17 23:23         ` Sam Bobroff
  0 siblings, 1 reply; 19+ messages in thread
From: Michael Neuling @ 2014-07-17 11:14 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: james.hogan, avagin, Paul.Clothier, Peter Zijlstra, Pedro Alves,
	oleg, akpm, Linux Kernel Mailing List, dhowells, Linux PPC dev,
	davej, tglx, David S. Miller, sam.bobroff, Anshuman Khandual

[-- Attachment #1: Type: text/plain, Size: 741 bytes --]

On Jul 17, 2014 9:11 PM, "Benjamin Herrenschmidt" <benh@kernel.crashing.org>
wrote:
>
> > >
> > >> Outstanding Issues
> > >> ==================
> > >> (1) Running DSCR register value inside a transaction does not seem
to be saved
> > >>     at thread.dscr when the process stops for ptrace examination.
> > >
> > > Hey Ben,
> > >
> > > Any updates on this patch series ?
> >
> > Ben,
> >
> > Any updates on this patch series ?
>
> I haven't had a chance to review yet, I was hoping somebody else would..
>
> Have you made any progress vs. the DSCR outstanding issue mentioned
> above ?

The DSCR issue should be resolved with Sam Bobroff's recent  DSCR fixes.
I've not tested them though.

Actually... Sam did you review this series?

Mikey

[-- Attachment #2: Type: text/html, Size: 1132 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
  2014-07-17 11:14       ` Michael Neuling
@ 2014-07-17 23:23         ` Sam Bobroff
  2014-07-18  8:13           ` Anshuman Khandual
  0 siblings, 1 reply; 19+ messages in thread
From: Sam Bobroff @ 2014-07-17 23:23 UTC (permalink / raw)
  To: Michael Neuling, Benjamin Herrenschmidt
  Cc: james.hogan, avagin, Paul.Clothier, David S. Miller,
	Peter Zijlstra, Pedro Alves, oleg, Linux Kernel Mailing List,
	dhowells, Linux PPC dev, davej, akpm, tglx, Anshuman Khandual

On 17/07/14 21:14, Michael Neuling wrote:
> 
> On Jul 17, 2014 9:11 PM, "Benjamin Herrenschmidt"
> <benh@kernel.crashing.org <mailto:benh@kernel.crashing.org>> wrote:
>>
>> > >
>> > >> Outstanding Issues
>> > >> ==================
>> > >> (1) Running DSCR register value inside a transaction does not
> seem to be saved
>> > >>     at thread.dscr when the process stops for ptrace examination.
>> > >
>> > > Hey Ben,
>> > >
>> > > Any updates on this patch series ?
>> >
>> > Ben,
>> >
>> > Any updates on this patch series ?
>>
>> I haven't had a chance to review yet, I was hoping somebody else would..
>>
>> Have you made any progress vs. the DSCR outstanding issue mentioned
>> above ?
> 
> The DSCR issue should be resolved with Sam Bobroff's recent  DSCR
> fixes.  I've not tested them though.
> 
> Actually... Sam did you review this series?
> 
> Mikey
> 

I did, and applying "powerpc: Correct DSCR during TM context switch"
corrected the DSCR value in the test program (the one in the patch notes
for this series).

(In fact, IIRC, the reason for my patch set was the bug exposed by this
one ;-)

Cheers,
Sam.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
  2014-07-17 23:23         ` Sam Bobroff
@ 2014-07-18  8:13           ` Anshuman Khandual
  0 siblings, 0 replies; 19+ messages in thread
From: Anshuman Khandual @ 2014-07-18  8:13 UTC (permalink / raw)
  To: Sam Bobroff, Michael Neuling, Benjamin Herrenschmidt
  Cc: james.hogan, avagin, Paul.Clothier, David S. Miller,
	Peter Zijlstra, Pedro Alves, oleg, Linux Kernel Mailing List,
	dhowells, Linux PPC dev, davej, akpm, tglx

On 07/18/2014 04:53 AM, Sam Bobroff wrote:
> On 17/07/14 21:14, Michael Neuling wrote:
>>
>> On Jul 17, 2014 9:11 PM, "Benjamin Herrenschmidt"
>> <benh@kernel.crashing.org <mailto:benh@kernel.crashing.org>> wrote:
>>>
>>>>>
>>>>>> Outstanding Issues
>>>>>> ==================
>>>>>> (1) Running DSCR register value inside a transaction does not
>> seem to be saved
>>>>>>     at thread.dscr when the process stops for ptrace examination.
>>>>>
>>>>> Hey Ben,
>>>>>
>>>>> Any updates on this patch series ?
>>>>
>>>> Ben,
>>>>
>>>> Any updates on this patch series ?
>>>
>>> I haven't had a chance to review yet, I was hoping somebody else would..
>>>
>>> Have you made any progress vs. the DSCR outstanding issue mentioned
>>> above ?
>>
>> The DSCR issue should be resolved with Sam Bobroff's recent  DSCR
>> fixes.  I've not tested them though.
>>
>> Actually... Sam did you review this series?
>>
>> Mikey
>>
> 
> I did, and applying "powerpc: Correct DSCR during TM context switch"
> corrected the DSCR value in the test program (the one in the patch notes
> for this series).
> 
> (In fact, IIRC, the reason for my patch set was the bug exposed by this
> one ;-)

Yeah the test program worked correctly with the fix from Sam. The first patch
is a generic code change which Pedro had reviewed before. The second and third
patches are powerpc specific.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
  2014-05-23 15:15 [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
                   ` (3 preceding siblings ...)
  2014-06-12  9:09 ` [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
@ 2014-07-24  6:52 ` Sam Bobroff
  2014-10-07 12:35   ` Anshuman Khandual
  2014-09-11  6:14 ` Anshuman Khandual
  5 siblings, 1 reply; 19+ messages in thread
From: Sam Bobroff @ 2014-07-24  6:52 UTC (permalink / raw)
  To: Anshuman Khandual, linux-kernel, linuxppc-dev, peterz, akpm, tglx
  Cc: mikey, james.hogan, avagin, Paul.Clothier, palves, oleg,
	dhowells, davej, davem

On 24/05/14 01:15, Anshuman Khandual wrote:
> 	This patch series adds five new ELF core note sections which can be
> used with existing ptrace request PTRACE_GETREGSET/SETREGSET for accessing
> various transactional memory and miscellaneous register sets on PowerPC
> platform. Please find a test program exploiting these new ELF core note
> types on a POWER8 system.
> 
> RFC: https://lkml.org/lkml/2014/4/1/292
> V1:  https://lkml.org/lkml/2014/4/2/43
> V2:  https://lkml.org/lkml/2014/5/5/88
> 
> Changes in V3
> =============
> (1) Added two new error paths in every TM related get/set functions when regset
>     support is not present on the system (ENODEV) or when the process does not
>     have any transaction active (ENODATA) in the context
> 
> (2) Installed the active hooks for all the newly added regset core note types
> 
> Changes in V2
> =============
> (1) Removed all the power specific ptrace requests corresponding to new NT_PPC_*
>     elf core note types. Now all the register sets can be accessed from ptrace
>     through PTRACE_GETREGSET/PTRACE_SETREGSET using the individual NT_PPC* core
>     note type instead
> (2) Fixed couple of attribute values for REGSET_TM_CGPR register set
> (3) Renamed flush_tmreg_to_thread as flush_tmregs_to_thread
> (4) Fixed 32 bit checkpointed GPR support
> (5) Changed commit messages accordingly
> 
> Outstanding Issues
> ==================
> (1) Running DSCR register value inside a transaction does not seem to be saved
>     at thread.dscr when the process stops for ptrace examination.

Since this is fixed by 96d016108640bc2b7fb0ee800737f80923847294, which
is already upstream, you might want to rebase and re-test. It should
pass and then you can remove the outstanding issues :-)

>     
> Test programs

program

When I posted the patch I mentioned above, I was asked to move the test
code into the powerpc kernel selftests so you may want to do this too.

Also, your test program covers everything mine did and more so you might
want to remove mine if you do add this to the selftests.

> =============
> #include <unistd.h>
> #include <stdlib.h>
> #include <string.h>
> #include <malloc.h>
> #include <errno.h>
> #include <sys/ptrace.h>
> #include <sys/uio.h>
> #include <sys/types.h>
> #include <sys/signal.h>
> #include <sys/user.h>

You should include sys/wait.h for waitpid().

> #include <linux/elf.h>
> #include <linux/types.h>
> #include <linux/ptrace.h>
> 
> typedef long long u64;
> typedef unsigned int u32;
> typedef __vector128 vector128;
> 
> /* TM CFPR */
> struct tm_cfpr {
> 	u64	fpr[32];
> 	u64	fpscr;
> };
> 
> /* TM CVMX */
> struct tm_cvmx {
>         vector128	vr[32] __attribute__((aligned(16)));
>         vector128	vscr __attribute__((aligned(16)));
> 	u32		vrsave;	
> };
> 
> /* TM SPR */
> struct tm_spr_regs {
> 	u64	tm_tfhar;
> 	u64	tm_texasr;
> 	u64	tm_tfiar;
> 	u64	tm_orig_msr;
> 	u64	tm_tar;
> 	u64	tm_ppr;
> 	u64	tm_dscr;
> };
> 
> /* Miscellaneous registers */
> struct misc_regs {
> 	u64	dscr;
> 	u64	ppr;
> 	u64	tar;
> };
> 
> /* TM instructions */
> #define TBEGIN          ".long 0x7C00051D ;"
> #define TEND            ".long 0x7C00055D ;"
> 
> /* SPR number */
> #define SPRN_DSCR	0x3
> #define SPRN_TAR	815
> 
> /* ELF core notes */
> #define NT_PPC_TM_SPR  0x103           /* PowerPC transactional memory special registers */
> #define NT_PPC_TM_CGPR 0x104           /* PowerpC transactional memory checkpointed GPR */
> #define NT_PPC_TM_CFPR 0x105           /* PowerPC transactional memory checkpointed FPR */
> #define NT_PPC_TM_CVMX 0x106           /* PowerPC transactional memory checkpointed VMX */
> #define NT_PPC_MISC    0x107           /* PowerPC miscellaneous registers */
> 
> #define VAL1 1
> #define VAL2 2
> #define VAL3 3
> #define VAL4 4
> 
> int main(int argc, char *argv[])
> {
> 	struct tm_spr_regs *tmr1;
> 	struct pt_regs *pregs1, *pregs2;
> 	struct tm_cfpr *fpr, *fpr1;
> 	struct misc_regs *dbr1;
> 	struct iovec iov;
> 
> 	pid_t child;
> 	int ret = 0, status = 0, i = 0, flag = 1;

status, i and flags are all unused.

> 
> 	pregs2 = (struct pt_regs *) malloc(sizeof(struct pt_regs));
> 	fpr = (struct tm_cfpr *) malloc(sizeof(struct tm_cfpr));
> 
> 	child = fork();
> 	if (child < 0) {
> 		printf("fork() failed \n");
> 		exit(-1);
> 	}
> 
> 	/* Child code */
> 	if (child == 0) {
> 		asm __volatile__(
> 			"6: ;"			/* TM checkpointed values */
> 			"li 1, %[val1];"	/* GPR[1] */
> 			".long 0x7C210166;"	/* FPR[1] */
> 			"li 2, %[val2];"	/* GPR[2] */
> 			".long 0x7C420166;"	/* FPR[2] */
> 			"mtspr %[tar], 1;"	/* TAR */
>  			"mtspr %[dscr], 2;"	/* DSCR */
> 			"1: ;"
> 			TBEGIN			/* TM running values */
> 			"beq 2f ;"
> 		 	"li 1, %[val3];"	/* GPR[1] */
>                         ".long 0x7C210166;"	/* FPR[1] */
>                         "li 2, %[val4];"	/* GPR[2] */
>                         ".long 0x7C420166;"	/* FPR[2] */
>                         "mtspr %[tar], 1;"	/* TAR */
> 			"mtspr %[dscr], 2;"	/* DSCR */
> 			"b .;"
> 			TEND
> 			"2: ;"			/* Abort handler */
> 			"b 1b;"			/* Start from TBEGIN */
> 
> 			"3: ;"
> 			"b 6b;"			/* Start all over again */
> 			:: [dscr]"i"(SPRN_DSCR), [tar]"i"(SPRN_TAR), [val1]"i"(VAL1), [val2]"i"(VAL2), [val3]"i"(VAL3), [val4]"i"(VAL4)
> 			: "memory", "r7");
> 	}
> 
> 	/* Parent */
> 	if (child) {
> 		do {
> 			memset(pregs2, 0 , sizeof(struct pt_regs));
> 			memset(fpr, 0 , sizeof(struct tm_cfpr));
> 
> 			/* Wait till child hits "b ." instruction */
> 			sleep(3);
> 
> 			/* Attach tracee */
> 			ret = ptrace(PTRACE_ATTACH, child, NULL, NULL);
> 			if (ret == -1) {
> 				printf("PTRACE_ATTACH failed: %s\n", strerror(errno));
> 				exit(-1);
> 			}
> 
> 			ret = waitpid(child, NULL, 0);
> 			if (ret != child) {
> 				printf("PID does not match\n");
> 				exit(-1);
> 			}
> 
> 			/* TM specific SPR */
> 			iov.iov_base = (struct tm_spr_regs *) malloc(sizeof(struct tm_spr_regs));
> 			iov.iov_len = sizeof(struct tm_spr_regs);
> 			ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_SPR, &iov);
> 			if (ret == -1) {
> 				printf("PTRACE_GETREGSET: NT_PPC_TM_SPR failed %s\n", strerror(errno));
> 				exit(-1);
> 			}
> 
> 			if (iov.iov_len != sizeof(struct tm_spr_regs)) {
> 				printf("NT_PPC_TM_SPR: Length returned is wrong\n");
> 				exit(-1);
> 			}
> 
> 			tmr1 = iov.iov_base;
> 			printf("-------TM specific SPR------\n");
> 			printf("TM TFHAR: %llx\n", tmr1->tm_tfhar);
> 			printf("TM TEXASR: %llx\n", tmr1->tm_texasr);
> 			printf("TM TFIAR: %llx\n", tmr1->tm_tfiar);
> 			printf("TM CH ORIG_MSR: %llx\n", tmr1->tm_orig_msr);
> 			printf("TM CH TAR: %llx\n", tmr1->tm_tar);
> 			printf("TM CH PPR: %llx\n", tmr1->tm_ppr);
> 			printf("TM CH DSCR: %llx\n", tmr1->tm_dscr);
> 
> 			if (tmr1->tm_tar == VAL1)
> 				printf("TAR PASSED\n");
> 			else
> 				printf("TAR FAILED\n");
> 
> 			if (tmr1->tm_dscr == VAL2)
> 				printf("DSCR PASSED\n");
> 			else
> 				printf("DSCR FAILED\n");
> 
> 			/* TM checkpointed GPR */
> 			iov.iov_base = (struct pt_regs *) malloc(sizeof(struct pt_regs));;
> 			iov.iov_len = sizeof(struct pt_regs);
> 			ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov);
> 			if (ret == -1) {
> 				printf("PTRACE_GETREGSET: NT_PPC_TM_CGPR failed: %s\n", strerror(errno));
> 				exit(-1);
> 			}
> 
> 			if (iov.iov_len != sizeof(struct pt_regs)) {
> 				printf("NT_PPC_TM_CGPR: Length returned is wrong\n");
> 				exit(-1);
> 			}
> 
> 			pregs1 = iov.iov_base;
> 			printf("-------TM checkpointed GPR-----\n");
> 			printf("TM CH GPR[1]: %x\n", pregs1->gpr[1]);
> 			printf("TM CH GPR[2]: %x\n", pregs1->gpr[2]);
> 			printf("TM CH NIP: %x\n", pregs1->nip);
> 			printf("TM CH LINK: %x\n", pregs1->link);
> 			printf("TM CH CCR: %x\n", pregs1->ccr);

I get a compiler warning for these printfs: they should be "%lx".

> 
> 			if (pregs1->gpr[1] == VAL1)
> 				printf("GPR[1] PASSED\n");
> 			else
> 				printf("GPR[1] FAILED\n");
> 
> 			if (pregs1->gpr[2] == VAL2)
> 				printf("GPR[2] PASSED\n");
> 			else
> 				printf("GPR[2] FAILED\n");
> 
> 			/* TM running GPR */
> 			ret = ptrace(PTRACE_GETREGS, child, NULL, pregs2);
> 			if (ret == -1) {
> 				printf("PTRACE_GETREGS fail: %s\n", strerror(errno));
> 				exit(-1);
> 			}
> 
> 			printf("-------TM running GPR-----\n");
> 			printf("TM RN GPR[1]: %x\n", pregs2->gpr[1]);
> 			printf("TM RN GPR[2]: %x\n", pregs2->gpr[2]);
> 			printf("TM RN NIP: %x\n", pregs2->nip);
> 			printf("TM RN LINK: %x\n", pregs2->link);
> 			printf("TM RN CCR: %x\n", pregs2->ccr);

Same as above, I get warnings and they should be "%lx".
> 
> 			
> 			if (pregs2->gpr[1] == VAL3)
> 				printf("GPR[1] PASSED\n");
> 			else
> 				printf("GPR[1] FAILED\n");
> 
> 			if (pregs2->gpr[2] == VAL4)
> 				printf("GPR[2] PASSED\n");
> 			else
> 				printf("GPR[2] FAILED\n");
> 
> 			/* TM checkpointed FPR */
> 			iov.iov_base = (struct tm_cfpr *) malloc(sizeof(struct tm_cfpr));;
> 			iov.iov_len = sizeof(struct tm_cfpr);
> 			ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov);
> 			if (ret == -1) {
> 				printf("PTRACE_GETREGSET: NT_PPC_TM_CFPR: Failed: %s\n", strerror(errno));
> 				exit(-1);
> 			}
> 
> 			if (iov.iov_len != sizeof(struct tm_cfpr)) {
> 				printf("NT_PPC_TM_CFPR: Length returned is wrong\n");
> 				exit(-1);
> 			}
> 
> 			fpr1 = iov.iov_base;
> 			printf("-------TM checkpointed FPR-----\n");
> 			printf("TM CH FPR[1]: %llx\n", fpr1->fpr[1]);
> 			printf("TM CH FPR[2]: %llx\n", fpr1->fpr[2]);
> 			printf("TM CH FPSCR: %llx\n", fpr1->fpscr);
> 
> 			if (fpr1->fpr[1] == VAL1)
> 				printf("FPR[1] PASSED\n");
> 			else
> 				printf("FPR[1] FAILED\n");
> 
> 			if (fpr1->fpr[2] == VAL2)
> 				printf("FPR[2] PASSED\n");
> 			else
> 				printf("FPR[2] FAILED\n");
> 
> 			/* TM running FPR */
> 			ret = ptrace(PTRACE_GETFPREGS, child, NULL, fpr);
> 			if (ret == -1) {
> 				printf("PTRACE_GETFPREGS failed: %s\n", strerror(errno));
> 				exit(-1);
> 			}
> 
> 			printf("-------TM running FPR-----\n");
> 			printf("TM RN FPR[1]: %llx\n", fpr->fpr[1]);
> 			printf("TM RN FPR[2]: %llx\n", fpr->fpr[2]);
> 			printf("TM RN FPSCR: %llx\n", fpr->fpscr);
> 
> 			if (fpr->fpr[1] == VAL3)
> 				printf("FPR[1] PASSED\n");
> 			else
> 				printf("FPR[1] FAILED\n");
> 
> 			if (fpr->fpr[2] == VAL4)
> 				printf("FPR[2] PASSED\n");
> 			else
> 				printf("FPR[2] FAILED\n");
> 
> 			/* Misc registers */
> 			iov.iov_base = (struct misc_regs *) malloc(sizeof(struct misc_regs));
> 			iov.iov_len = sizeof(struct misc_regs);
> 			ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_MISC, &iov);
> 			if (ret == -1) {
> 				printf("PTRACE_GETREGSET: NT_PPC_MISC: Failed: %s\n", strerror(errno));
> 				exit(-1);
> 			}
> 
> 			if (iov.iov_len != sizeof(struct misc_regs)) {
> 				printf("NT_PPC_TM_MISC: Length returned is wrong\n");
> 				exit(-1);
> 			}
> 
> 			dbr1  = iov.iov_base;
> 			printf("-------Running miscellaneous registers-------\n");
> 			printf("TM RN DSCR: %llx\n", dbr1->dscr);
> 			printf("TM RN PPR: %llx\n", dbr1->ppr);
> 			printf("TM RN TAR: %llx\n", dbr1->tar);
> 
> 			if (dbr1->tar == VAL3)
> 				printf("TAR PASSED\n");
> 			else
> 				printf("TAR FAILED\n");
> 
> 			if (dbr1->dscr == VAL4)
> 				printf("DSCR PASSED\n");
> 			else
> 				printf("DSCR FAILED\n");
> 
> 			/* Detach tracee */
> 			ret = ptrace(PTRACE_DETACH, child, NULL, NULL);
> 			if (ret == -1) {
> 				printf("PTRACE_DETACH failed: %s\n", strerror(errno));
> 				exit(-1);
> 			}
> 		} while (0);
> 	}
> 	return 0;
> }
> 
> Test Results
> ============
> (1) 64 bit application ==>
> 
> -------TM specific SPR------
> TM TFHAR: 10000960
> TM TEXASR: de000001ac000001
> TM TFIAR: c0000000000465f6
> TM CH ORIG_MSR: 900000050000f032
> TM CH TAR: 1
> TM CH PPR: c000000000000
> TM CH DSCR: 2
> TAR PASSED
> DSCR PASSED
> -------TM checkpointed GPR-----
> TM CH GPR[1]: 1
> TM CH GPR[2]: 2
> TM CH NIP: 10000960
> TM CH LINK: 10000904
> TM CH CCR: 22000422
> GPR[1] PASSED
> GPR[2] PASSED
> -------TM running GPR-----
> TM RN GPR[1]: 3
> TM RN GPR[2]: 4
> TM RN NIP: 1000097c
> TM RN LINK: 10000904
> TM RN CCR: 2000422
> GPR[1] PASSED
> GPR[2] PASSED
> -------TM checkpointed FPR-----
> TM CH FPR[1]: 1
> TM CH FPR[2]: 2
> TM CH FPSCR: 0
> FPR[1] PASSED
> FPR[2] PASSED
> -------TM running FPR-----
> TM RN FPR[1]: 3
> TM RN FPR[2]: 4
> TM RN FPSCR: 0
> FPR[1] PASSED
> FPR[2] PASSED
> -------Running miscellaneous registers-------
> TM RN DSCR: 0
> TM RN PPR: c000000000000
> TM RN TAR: 3
> TAR PASSED
> DSCR FAILED
> 
> (2) 32 bit application ==>
> 
> -------TM specific SPR------
> TM TFHAR: 100006b8
> TM TEXASR: de000001ac000001
> TM TFIAR: c0000000000465f6
> TM CH ORIG_MSR: 100000050000f032
> TM CH TAR: 1
> TM CH PPR: c000000000000
> TM CH DSCR: 2
> TAR PASSED
> DSCR PASSED
> -------TM checkpointed GPR-----
> TM CH GPR[1]: 1
> TM CH GPR[2]: 2
> TM CH NIP: 100006b8
> TM CH LINK: 1000066c
> TM CH CCR: 22000422
> GPR[1] PASSED
> GPR[2] PASSED
> -------TM running GPR-----
> TM RN GPR[1]: 3
> TM RN GPR[2]: 4
> TM RN NIP: 100006d4
> TM RN LINK: 1000066c
> TM RN CCR: 2000422
> GPR[1] PASSED
> GPR[2] PASSED
> -------TM checkpointed FPR-----
> TM CH FPR[1]: 1
> TM CH FPR[2]: 2
> TM CH FPSCR: 0
> FPR[1] PASSED
> FPR[2] PASSED
> -------TM running FPR-----
> TM RN FPR[1]: 3
> TM RN FPR[2]: 4
> TM RN FPSCR: 0
> FPR[1] PASSED
> FPR[2] PASSED
> -------Running miscellaneous registers-------
> TM RN DSCR: 0
> TM RN PPR: c000000000000
> TM RN TAR: 3
> TAR PASSED
> DSCR FAILED
> 
> 
> Anshuman Khandual (3):
>   elf: Add some new PowerPC specifc note sections
>   powerpc, ptrace: Enable support for transactional memory register sets
>   powerpc, ptrace: Enable support for miscellaneous registers
> 
>  arch/powerpc/include/asm/switch_to.h |   8 +
>  arch/powerpc/kernel/process.c        |  24 +
>  arch/powerpc/kernel/ptrace.c         | 873 +++++++++++++++++++++++++++++++++--
>  include/uapi/linux/elf.h             |   5 +
>  4 files changed, 881 insertions(+), 29 deletions(-)
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 2/3] powerpc, ptrace: Enable support for transactional memory register sets
  2014-05-23 15:15 ` [PATCH V3 2/3] powerpc, ptrace: Enable support for transactional memory register sets Anshuman Khandual
@ 2014-07-24  6:56   ` Sam Bobroff
  2014-08-27 21:35   ` Sukadev Bhattiprolu
  1 sibling, 0 replies; 19+ messages in thread
From: Sam Bobroff @ 2014-07-24  6:56 UTC (permalink / raw)
  To: Anshuman Khandual, linux-kernel, linuxppc-dev, peterz, akpm, tglx
  Cc: mikey, james.hogan, avagin, Paul.Clothier, palves, oleg,
	dhowells, davej, davem

On 24/05/14 01:15, Anshuman Khandual 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@linux.vnet.ibm.com>

Hi Anshuman,

I'm not Ben but I've reviewed your patch as well as I can and I have
some comments that might be useful to you.

First of all, I couldn't get this to compile without CONFIG_VSX and
CONFIG_PPC_TRANSACTIONAL_MEM defined: there are obvious typos ("esle"
instead of "else") and references to fields that aren't defined for
those cases. I haven't mentioned any of those issues below as the
compiler will do that but you should definitely test those configurations.

Also some of the code seems to assume that if CONFIG_VSX is defined then
CONFIG_PPC_TRANSACTIONAL_MEM must also be defined, but that isn't the
case (it's the other way round: CONFIG_PPC_TRANSACTIONAL_MEM implies
CONFIG_VSX).

> ---
>  arch/powerpc/include/asm/switch_to.h |   8 +
>  arch/powerpc/kernel/process.c        |  24 ++
>  arch/powerpc/kernel/ptrace.c         | 792 +++++++++++++++++++++++++++++++++--
>  3 files changed, 795 insertions(+), 29 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
> index 0e83e7d..2737f46 100644
> --- a/arch/powerpc/include/asm/switch_to.h
> +++ b/arch/powerpc/include/asm/switch_to.h
> @@ -80,6 +80,14 @@ static inline void flush_spe_to_thread(struct task_struct *t)
>  }
>  #endif
>  
> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> +extern void flush_tmregs_to_thread(struct task_struct *);
> +#else
> +static inline void flush_tmregs_to_thread(struct task_struct *t)
> +{
> +}
> +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
> +
>  static inline void clear_task_ebb(struct task_struct *t)
>  {
>  #ifdef CONFIG_PPC_BOOK3S_64
> diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
> index 31d0215..e247898 100644
> --- a/arch/powerpc/kernel/process.c
> +++ b/arch/powerpc/kernel/process.c
> @@ -695,6 +695,30 @@ static inline void __switch_to_tm(struct task_struct *prev)
>  	}
>  }
>  
> +void flush_tmregs_to_thread(struct task_struct *tsk)
> +{
> +	/*
> +	 * If task is not current, it should have been flushed
> +	 * already to it's thread_struct during __switch_to().
> +	 */
> +	if (tsk != current)
> +		return;
> +
> +	preempt_disable();
> +	if (tsk->thread.regs) {
> +		/*
> +		 * If we are still current, the TM state need to
> +		 * be flushed to thread_struct as it will be still
> +		 * present in the current cpu.
> +		 */
> +		if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
> +			__switch_to_tm(tsk);
> +			tm_recheckpoint_new_task(tsk);

There is at least one other usage of this pair of calls in order to
"flush" the TM state (in arch_dup_task_struct()), so rather than copying
it you might want to create a new function and call it from both places.
(And include the nice comment from arch_dup_task_struct() that explains
how it works and why.)

> +		}
> +	}
> +	preempt_enable();
> +}
> +
>  /*
>   * This is called if we are on the way out to userspace and the
>   * TIF_RESTORE_TM flag is set.  It checks if we need to reload
> diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
> index 2e3d2bf..17642ef 100644
> --- a/arch/powerpc/kernel/ptrace.c
> +++ b/arch/powerpc/kernel/ptrace.c
> @@ -357,6 +357,17 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
>  	return ret;
>  }
>  
> +/*
> + * When any transaction is active, "thread_struct->transact_fp" holds
> + * the current running value of all FPR registers and "thread_struct->
> + * fp_state" holds the last checkpointed FPR registers state for the
> + * current transaction.
> + *
> + * struct data {
> + * 	u64	fpr[32];
> + * 	u64	fpscr;
> + * };

It would be nice to say why you've included "struct data" in the comment.

> + */
>  static int fpr_get(struct task_struct *target, const struct user_regset *regset,
>  		   unsigned int pos, unsigned int count,
>  		   void *kbuf, void __user *ubuf)
> @@ -365,21 +376,41 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
>  	u64 buf[33];
>  	int i;
>  #endif
> -	flush_fp_to_thread(target);
> +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> +		flush_fp_to_thread(target);
> +		flush_altivec_to_thread(target);
> +		flush_tmregs_to_thread(target);
> +	} else {
> +		flush_fp_to_thread(target);
> +	}

I don't see why you need the else. Could this be:

	flush_fp_to_thread(target);
	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
		flush_altivec_to_thread(target);
		flush_tmregs_to_thread(target);
	}

>  
>  #ifdef CONFIG_VSX
>  	/* 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;
> +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> +		for (i = 0; i < 32 ; i++)
> +			buf[i] = target->thread.TS_TRANS_FPR(i);
> +		buf[32] = target->thread.transact_fp.fpscr;
> +	} else {
> +		for (i = 0; i < 32 ; i++)
> +			buf[i] = target->thread.TS_FPR(i);
> +		buf[32] = target->thread.fp_state.fpscr;
> +	}

I see several cases of similar code needing to access either fp_state or
transact_fp, or other similar pairs, so maybe you could use a macro.
Something like this (I'm not sure about the name!):

#define MABYE_TM(TSK,X,TM_X) \
((MSR_TM_ACTIVE((TSK)->thread.regs->msr) \
? &((TSK)->thread.(TM_X) \
: &((TSK)->thread.(X))

Then you could do this:

	struct thread_fp_state *fp;

	fp = MAYBE_TM(target,fp_state,transact_fp);
	for (i = 0; i < 32; i++)
		buf[i] = (*fp)[i][TS_FPROFFSET];

>  	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
>  
>  #else
> -	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> -		     offsetof(struct thread_fp_state, fpr[32][0]));
> +	if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
> +		BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
> +				offsetof(struct transact_fp, fpr[32][0]));
>  
> -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> +		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> +				   &target->thread.transact_fp, 0, -1);
> +	} esle {
> +		BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> +			     offsetof(struct thread_fp_state, fpr[32][0]));
> +
> +		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
>  				   &target->thread.fp_state, 0, -1);
> +	}

The BUILD_BUG_ON() statements don't need to be in the "if", since
they're compile-time (and "struct transact_fp" is not a type so that one
isn't needed), and you could use the utility function (above) to shorten
this a lot, i.e.:
	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
		     offsetof(struct thread_fp_state, fpr[32][0]));
	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  MAYBE_TM(target,fp_state,transact_fp)
				   , 0, -1);

>  #endif
>  }
>  
> @@ -391,23 +422,44 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
>  	u64 buf[33];
>  	int i;
>  #endif
> -	flush_fp_to_thread(target);
> +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> +		flush_fp_to_thread(target);
> +		flush_altivec_to_thread(target);
> +		flush_tmregs_to_thread(target);
> +	} else {
> +		flush_fp_to_thread(target);
> +	}

This could be simplified like the similar case above.

>  #ifdef CONFIG_VSX
>  	/* 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];
> +	for (i = 0; i < 32 ; i++) {
> +		if (MSR_TM_ACTIVE(target->thread.regs->msr))
> +			target->thread.TS_TRANS_FPR(i) = buf[i];
> +		else
> +			target->thread.TS_FPR(i) = buf[i];
> +	}
> +	if (MSR_TM_ACTIVE(target->thread.regs->msr))
> +		target->thread.transact_fp.fpscr = buf[32];
> +	else
> +		target->thread.fp_state.fpscr = buf[32];
>  	return 0;

This could be shorted using the above macro.

>  #else
> -	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> -		     offsetof(struct thread_fp_state, fpr[32][0]));
> +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> +		BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
> +			     offsetof(struct transact_fp, fpr[32][0]));
>  
> -	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> -				  &target->thread.fp_state, 0, -1);
> +		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> +					  &target->thread.transact_fp, 0, -1);
> +	} else {
> +		BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> +			     offsetof(struct thread_fp_state, fpr[32][0]));
> +
> +		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> +				&target->thread.fp_state, 0, -1);
> +	}
>  #endif

... as could this.

>  }
>  
> @@ -432,20 +484,44 @@ static int vr_active(struct task_struct *target,
>  	return target->thread.used_vr ? regset->n : 0;
>  }
>  
> +/*
> + * When any transaction is active, "thread_struct->transact_vr" holds
> + * the current running value of all VMX registers and "thread_struct->
> + * vr_state" holds the last checkpointed value of VMX registers for the
> + * current transaction.
> + *
> + * struct data {
> + * 	vector128	vr[32];
> + * 	vector128	vscr;
> + * 	vector128	vrsave;
> + * };
> + */

Again a comment about "struct data" would be nice.

>  static int vr_get(struct task_struct *target, const struct user_regset *regset,
>  		  unsigned int pos, unsigned int count,
>  		  void *kbuf, void __user *ubuf)
>  {
>  	int ret;
> +	struct thread_vr_state *addr;
>  
> -	flush_altivec_to_thread(target);
> +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> +		flush_fp_to_thread(target);
> +		flush_altivec_to_thread(target);
> +		flush_tmregs_to_thread(target);
> +	} else {
> +		flush_altivec_to_thread(target);
> +	}

As above.

>  
>  	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
>  		     offsetof(struct thread_vr_state, vr[32]));
>  
> +	if (MSR_TM_ACTIVE(target->thread.regs->msr))
> +		addr = &target->thread.transact_vr;
> +	else
> +		addr = &target->thread.vr_state;
> +
>  	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> -				  &target->thread.vr_state, 0,
> -				  33 * sizeof(vector128));
> +				addr, 0, 33 * sizeof(vector128));
> +

As above.

>  	if (!ret) {
>  		/*
>  		 * Copy out only the low-order word of vrsave.
> @@ -455,11 +531,14 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
>  			u32 word;
>  		} vrsave;
>  		memset(&vrsave, 0, sizeof(vrsave));
> -		vrsave.word = target->thread.vrsave;
> +		if (MSR_TM_ACTIVE(target->thread.regs->msr))
> +			vrsave.word = target->thread.transact_vrsave;
> +		else
> +			vrsave.word = target->thread.vrsave;
> +

As above.

>  		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
>  					  33 * sizeof(vector128), -1);
>  	}
> -
>  	return ret;
>  }
>  
> @@ -467,16 +546,27 @@ 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)
>  {
> +	struct thread_vr_state *addr;
>  	int ret;
>  
> -	flush_altivec_to_thread(target);
> +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> +		flush_fp_to_thread(target);
> +		flush_altivec_to_thread(target);
> +		flush_tmregs_to_thread(target);
> +	} else {
> +		flush_altivec_to_thread(target);
> +	}

Could flush_altivec_to_thread() be pulled out of the "if" or is it
important to call flush_fp_to_thread() first?

>  
>  	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
>  		     offsetof(struct thread_vr_state, vr[32]));
>  
> +	if (MSR_TM_ACTIVE(target->thread.regs->msr))
> +		addr = &target->thread.transact_vr;
> +	else
> +		addr = &target->thread.vr_state;
>  	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> -				 &target->thread.vr_state, 0,
> -				 33 * sizeof(vector128));
> +			addr, 0, 33 * sizeof(vector128));
> +

As above, and as a result you could remove "addr".

>  	if (!ret && count > 0) {
>  		/*
>  		 * We use only the first word of vrsave.
> @@ -486,13 +576,21 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
>  			u32 word;
>  		} vrsave;
>  		memset(&vrsave, 0, sizeof(vrsave));
> -		vrsave.word = target->thread.vrsave;
> +
> +		if (MSR_TM_ACTIVE(target->thread.regs->msr))
> +			vrsave.word = target->thread.transact_vrsave;
> +		else
> +			vrsave.word = target->thread.vrsave;
> +

As above.

>  		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
>  					 33 * sizeof(vector128), -1);
> -		if (!ret)
> -			target->thread.vrsave = vrsave.word;
> +		if (!ret) {
> +			if (MSR_TM_ACTIVE(target->thread.regs->msr))
> +				target->thread.transact_vrsave = vrsave.word;
> +			else
> +				target->thread.vrsave = vrsave.word;
> +		}

As above.

>  	}
> -
>  	return ret;
>  }
>  #endif /* CONFIG_ALTIVEC */
> @@ -613,6 +711,442 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
>  }
>  #endif /* CONFIG_SPE */
>  
> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> +
> +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;
> +}
> +/*
> + *  Transactional memory SPR
> + *
> + * 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;
> +
> +	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);
> +
> +	/* TFHAR register */
> +	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> +			&target->thread.tm_tfhar, 0, sizeof(u64));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar) +
> +			sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
> +
> +	/* TEXASR register */
> +	if (!ret)
> +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> +			&target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr) +
> +			sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
> +
> +	/* TFIAR register */
> +	if (!ret)
> +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> +			&target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar) +
> +			sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
> +
> +	/* 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));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr) +
> +			sizeof(unsigned long) + sizeof(struct pt_regs)
> +				!= offsetof(struct thread_struct, tm_tar));
> +
> +	/* 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));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
> +			+ sizeof(unsigned long) !=
> +				offsetof(struct thread_struct, tm_ppr));
> +
> +	/* 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));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
> +			sizeof(unsigned long) !=
> +				offsetof(struct thread_struct, tm_dscr));
> +
> +	/* 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;
> +}
> +
> +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;
> +
> +	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);
> +
> +	/* TFHAR register */
> +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> +				&target->thread.tm_tfhar, 0, sizeof(u64));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar)
> +		+ sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
> +
> +	/* TEXASR register */
> +	if (!ret)
> +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> +			&target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr)
> +		+ sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
> +
> +	/* TFIAR register */
> +	if (!ret)
> +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> +			&target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar)
> +		+ sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
> +
> +	/* 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));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr)
> +		+ sizeof(unsigned long) + sizeof(struct pt_regs) !=
> +			offsetof(struct thread_struct, tm_tar));
> +
> +	/* 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));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
> +			+ sizeof(unsigned long) != offsetof(struct thread_struct, tm_ppr));
> +
> +	/* 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));
> +
> +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
> +			sizeof(unsigned long) !=
> +				offsetof(struct thread_struct, tm_dscr));
> +
> +	/* 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;
> +}

I don't understand why tm_spr_set() and tm_spr_get() are structured like
this. It looks like they're expecting user_regset_copyin() to fail part
of the way through and are being careful to set the registers until that
point, even if it's going to return a failure.

This seems strange because other functions are careful to construct an
intermediate buffer so that they can either succeed or fail entirely. If
there's a reason that this needs to be this way, it might be a good idea
to explain that in a comment.

If they dont need to act like that, wouldn't all the BUILD_BUG_ONs
guarantee that the thread_struct registers are contiguous and therefore
you could set them all with a single call to user_regset_copyin()? If
you don't need them to be contiguous then what are the BUILD_BUG_ONs for?

> +
> +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 Checkpointed GPR
> + *
> + * 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);

I see this pattern of checking for TM and calling flush_fp_to_thread(),
flush_altivec_to_thread() and flush_tmregs_to_thread() in many places;
maybe it should be factored out to a function.

> +	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> +			&target->thread.ckpt_regs, 0,
> +				sizeof(struct pt_regs));
> +	return ret;
> +}
> +
> +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;
> +}
> +
> +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 Checkpointed FPR
> + *
> + * 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)
> +{
> +#ifdef CONFIG_VSX
> +	u64 buf[33];
> +	int i;
> +#endif
> +	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);
> +
> +#ifdef CONFIG_VSX
> +	/* 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);
> +
> +#else
> +	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> +		offsetof(struct thread_fp_state, fpr[32][0]));
> +
> +	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> +			&target->thread.thread_fp_state, 0, -1);
> +#endif
> +}
> +
> +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)
> +{
> +#ifdef CONFIG_VSX
> +	u64 buf[33];
> +	int i;
> +#endif
> +	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);
> +
> +#ifdef CONFIG_VSX
> +	/* 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;
> +#else
> +	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> +		      offsetof(struct thread_fp_state, fpr[32][0]));
> +
> +	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> +				&target->thread.fp_state, 0, -1);
> +#endif
> +}
> +
> +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 Checkpointed VMX
> + *
> + * 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;
> +
> +	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);
> +
> +	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
> +		     offsetof(struct thread_vr_state, vr[32]));
> +
> +	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);

I see this pattern of returning only the low-order word several times.
Maybe it should be factored out, or there is already a function
somewhere to do this (it seems like a fairly generic operation).

> +	}
> +	return ret;
> +}
> +
> +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;
> +
> +	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);
> +
> +	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
> +		offsetof(struct thread_vr_state, vr[32]));
> +
> +	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.
> +		 */
> +		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.
> @@ -629,6 +1163,12 @@ enum powerpc_regset {
>  #ifdef CONFIG_SPE
>  	REGSET_SPE,
>  #endif
> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> +	REGSET_TM_SPR,		/* TM specific SPR */
> +	REGSET_TM_CGPR,		/* TM checkpointed GPR */
> +	REGSET_TM_CFPR,		/* TM checkpointed FPR */
> +	REGSET_TM_CVMX,		/* TM checkpointed VMX */
> +#endif
>  };
>  
>  static const struct user_regset native_regsets[] = {
> @@ -663,6 +1203,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 = 7,
> +		.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 = 34,
> +		.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 = {
> @@ -690,7 +1252,7 @@ static int gpr32_get(struct task_struct *target,
>  	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; 
> +			target->thread.regs->gpr[i] = NV_REG_POISON;
>  	}
>  
>  	pos /= sizeof(reg);
> @@ -803,6 +1365,157 @@ static int gpr32_set(struct task_struct *target,
>  					 (PT_TRAP + 1) * sizeof(reg), -1);
>  }
>  
> +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)
> +{
> +	const unsigned long *regs = &target->thread.ckpt_regs.gpr[0];
> +	compat_ulong_t *k = kbuf;
> +	compat_ulong_t __user *u = ubuf;
> +	compat_ulong_t reg;
> +	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);
> +
> +	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; 

The line above adds a whitespace error. (Did you run it through
checkpatch.pl?)

> +	}
> +
> +	pos /= sizeof(reg);
> +	count /= sizeof(reg);
> +
> +	if (kbuf)
> +		for (; count > 0 && pos < PT_MSR; --count)
> +			*k++ = regs[pos++];
> +	else
> +		for (; count > 0 && pos < PT_MSR; --count)
> +			if (__put_user((compat_ulong_t) regs[pos++], u++))
> +				return -EFAULT;
> +
> +	if (count > 0 && pos == PT_MSR) {
> +		reg = get_user_msr(target);
> +		if (kbuf)
> +			*k++ = reg;
> +		else if (__put_user(reg, u++))
> +			return -EFAULT;
> +		++pos;
> +		--count;
> +	}
> +
> +	if (kbuf)
> +		for (; count > 0 && pos < PT_REGS_COUNT; --count)
> +			*k++ = regs[pos++];
> +	else
> +		for (; count > 0 && pos < PT_REGS_COUNT; --count)
> +			if (__put_user((compat_ulong_t) regs[pos++], u++))
> +				return -EFAULT;
> +
> +	kbuf = k;
> +	ubuf = u;
> +	pos *= sizeof(reg);
> +	count *= sizeof(reg);
> +	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
> +					PT_REGS_COUNT * sizeof(reg), -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)
> +{
> +	unsigned long *regs = &target->thread.ckpt_regs.gpr[0];
> +	const compat_ulong_t *k = kbuf;
> +	const compat_ulong_t __user *u = ubuf;
> +	compat_ulong_t reg;
> +
> +	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);
> +
> +	if (target->thread.regs == NULL)
> +		return -EIO;
> +
> +	CHECK_FULL_REGS(target->thread.regs);
> +
> +	pos /= sizeof(reg);
> +	count /= sizeof(reg);
> +
> +	if (kbuf)
> +		for (; count > 0 && pos < PT_MSR; --count)
> +			regs[pos++] = *k++;
> +	else
> +		for (; count > 0 && pos < PT_MSR; --count) {
> +			if (__get_user(reg, u++))
> +				return -EFAULT;
> +			regs[pos++] = reg;
> +		}
> +
> +
> +	if (count > 0 && pos == PT_MSR) {
> +		if (kbuf)
> +			reg = *k++;
> +		else if (__get_user(reg, u++))
> +			return -EFAULT;
> +		set_user_msr(target, reg);
> +		++pos;
> +		--count;
> +	}
> +
> +	if (kbuf) {
> +		for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
> +			regs[pos++] = *k++;
> +		for (; count > 0 && pos < PT_TRAP; --count, ++pos)
> +			++k;
> +	} else {
> +		for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
> +			if (__get_user(reg, u++))
> +				return -EFAULT;
> +			regs[pos++] = reg;
> +		}
> +		for (; count > 0 && pos < PT_TRAP; --count, ++pos)
> +			if (__get_user(reg, u++))
> +				return -EFAULT;
> +	}
> +
> +	if (count > 0 && pos == PT_TRAP) {
> +		if (kbuf)
> +			reg = *k++;
> +		else if (__get_user(reg, u++))
> +			return -EFAULT;
> +		set_user_trap(target, reg);
> +		++pos;
> +		--count;
> +	}
> +
> +	kbuf = k;
> +	ubuf = u;
> +	pos *= sizeof(reg);
> +	count *= sizeof(reg);
> +	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
> +					 (PT_TRAP + 1) * sizeof(reg), -1);
> +}
> +
> +
>  /*
>   * These are the regset flavors matching the CONFIG_PPC32 native set.
>   */
> @@ -831,6 +1544,28 @@ 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 = 7,
> +		.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 = 34,
> +		.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 = {
> @@ -1754,7 +2489,6 @@ long arch_ptrace(struct task_struct *child, long request,
>  					     REGSET_SPE, 0, 35 * sizeof(u32),
>  					     datavp);
>  #endif
> -
>  	default:
>  		ret = ptrace_request(child, request, addr, data);
>  		break;
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 2/3] powerpc, ptrace: Enable support for transactional memory register sets
  2014-05-23 15:15 ` [PATCH V3 2/3] powerpc, ptrace: Enable support for transactional memory register sets Anshuman Khandual
  2014-07-24  6:56   ` Sam Bobroff
@ 2014-08-27 21:35   ` Sukadev Bhattiprolu
  2014-10-09  5:04     ` Anshuman Khandual
  1 sibling, 1 reply; 19+ messages in thread
From: Sukadev Bhattiprolu @ 2014-08-27 21:35 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: mikey, james.hogan, avagin, Paul.Clothier, davem, peterz, palves,
	linux-kernel, oleg, dhowells, linuxppc-dev, davej, akpm, tglx

Anshuman Khandual [khandual@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 <khandual@linux.vnet.ibm.com>
| ---
|  arch/powerpc/include/asm/switch_to.h |   8 +
|  arch/powerpc/kernel/process.c        |  24 ++
|  arch/powerpc/kernel/ptrace.c         | 792 +++++++++++++++++++++++++++++++++--
|  3 files changed, 795 insertions(+), 29 deletions(-)
| 
| diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
| index 0e83e7d..2737f46 100644
| --- a/arch/powerpc/include/asm/switch_to.h
| +++ b/arch/powerpc/include/asm/switch_to.h
| @@ -80,6 +80,14 @@ static inline void flush_spe_to_thread(struct task_struct *t)
|  }
|  #endif
|  
| +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
| +extern void flush_tmregs_to_thread(struct task_struct *);
| +#else
| +static inline void flush_tmregs_to_thread(struct task_struct *t)
| +{
| +}
| +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
| +
|  static inline void clear_task_ebb(struct task_struct *t)
|  {
|  #ifdef CONFIG_PPC_BOOK3S_64
| diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
| index 31d0215..e247898 100644
| --- a/arch/powerpc/kernel/process.c
| +++ b/arch/powerpc/kernel/process.c
| @@ -695,6 +695,30 @@ static inline void __switch_to_tm(struct task_struct *prev)
|  	}
|  }
|  
| +void flush_tmregs_to_thread(struct task_struct *tsk)
| +{
| +	/*
| +	 * If task is not current, it should have been flushed
| +	 * already to it's thread_struct during __switch_to().
| +	 */
| +	if (tsk != current)
| +		return;
| +
| +	preempt_disable();
| +	if (tsk->thread.regs) {
| +		/*
| +		 * If we are still current, the TM state need to
| +		 * be flushed to thread_struct as it will be still
| +		 * present in the current cpu.
| +		 */
| +		if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
| +			__switch_to_tm(tsk);
| +			tm_recheckpoint_new_task(tsk);
| +		}
| +	}
| +	preempt_enable();
| +}
| +
|  /*
|   * This is called if we are on the way out to userspace and the
|   * TIF_RESTORE_TM flag is set.  It checks if we need to reload
| diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
| index 2e3d2bf..17642ef 100644
| --- a/arch/powerpc/kernel/ptrace.c
| +++ b/arch/powerpc/kernel/ptrace.c
| @@ -357,6 +357,17 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
|  	return ret;
|  }
|  
| +/*
| + * When any transaction is active, "thread_struct->transact_fp" holds
| + * the current running value of all FPR registers and "thread_struct->
| + * fp_state" holds the last checkpointed FPR registers state for the
| + * current transaction.
| + *
| + * struct data {
| + * 	u64	fpr[32];
| + * 	u64	fpscr;
| + * };
| + */

Maybe a reference to 'struct thread_fp_state' in the comments will help ?


|  static int fpr_get(struct task_struct *target, const struct user_regset *regset,
|  		   unsigned int pos, unsigned int count,
|  		   void *kbuf, void __user *ubuf)
| @@ -365,21 +376,41 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
|  	u64 buf[33];
|  	int i;
|  #endif
| -	flush_fp_to_thread(target);
| +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
| +		flush_fp_to_thread(target);
| +		flush_altivec_to_thread(target);
| +		flush_tmregs_to_thread(target);
| +	} else {
| +		flush_fp_to_thread(target);
| +	}

flush_fp_to_thread(target) is uncondtional - so could be outside
the if and else blocks ?

|  
|  #ifdef CONFIG_VSX
|  	/* 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;
| +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
| +		for (i = 0; i < 32 ; i++)
| +			buf[i] = target->thread.TS_TRANS_FPR(i);
| +		buf[32] = target->thread.transact_fp.fpscr;
| +	} else {
| +		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);
|  
|  #else
| -	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
| -		     offsetof(struct thread_fp_state, fpr[32][0]));
| +	if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
| +		BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
| +				offsetof(struct transact_fp, fpr[32][0]));

Is MSR_TM_ACTIVE() a run time check or compile time ?
ie is there a reason to move the compile time check into the if block ?

|  
| -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +				   &target->thread.transact_fp, 0, -1);
| +	} esle {
| +		BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
| +			     offsetof(struct thread_fp_state, fpr[32][0]));
| +
| +		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|  				   &target->thread.fp_state, 0, -1);
| +	}
|  #endif
|  }
|  
| @@ -391,23 +422,44 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
|  	u64 buf[33];
|  	int i;
|  #endif
| -	flush_fp_to_thread(target);
| +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
| +		flush_fp_to_thread(target);
| +		flush_altivec_to_thread(target);
| +		flush_tmregs_to_thread(target);
| +	} else {
| +		flush_fp_to_thread(target);
| +	}
|  

As mentioned above, flush_fp_to_thread() could be outside the if block.
|  #ifdef CONFIG_VSX
|  	/* 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];
| +	for (i = 0; i < 32 ; i++) {
| +		if (MSR_TM_ACTIVE(target->thread.regs->msr))
| +			target->thread.TS_TRANS_FPR(i) = buf[i];
| +		else
| +			target->thread.TS_FPR(i) = buf[i];
| +	}
| +	if (MSR_TM_ACTIVE(target->thread.regs->msr))
| +		target->thread.transact_fp.fpscr = buf[32];
| +	else
| +		target->thread.fp_state.fpscr = buf[32];

I think this code is easier to read than the similar code above
in fpr_get() where you have the 'for' loop in both if and else blocks.

|  	return 0;
|  #else
| -	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
| -		     offsetof(struct thread_fp_state, fpr[32][0]));
| +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
| +		BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
| +			     offsetof(struct transact_fp, fpr[32][0]));
|  
| -	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| -				  &target->thread.fp_state, 0, -1);
| +		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +					  &target->thread.transact_fp, 0, -1);
| +	} else {
| +		BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
| +			     offsetof(struct thread_fp_state, fpr[32][0]));
| +
| +		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +				&target->thread.fp_state, 0, -1);
| +	}
|  #endif
|  }
|  
| @@ -432,20 +484,44 @@ static int vr_active(struct task_struct *target,
|  	return target->thread.used_vr ? regset->n : 0;
|  }
|  
| +/*
| + * When any transaction is active, "thread_struct->transact_vr" holds
| + * the current running value of all VMX registers and "thread_struct->
| + * vr_state" holds the last checkpointed value of VMX registers for the
| + * current transaction.
| + *
| + * 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)
|  {
|  	int ret;
| +	struct thread_vr_state *addr;
|  
| -	flush_altivec_to_thread(target);
| +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
| +		flush_fp_to_thread(target);
| +		flush_altivec_to_thread(target);

Is order of flush_fp_to_thread() and flush_altivec_to_thread()
significant or can we call flush_altivec_to_thread() unconditionally
outside the if block ?
| +		flush_tmregs_to_thread(target);
| +	} else {
| +		flush_altivec_to_thread(target);
| +	}
|  
|  	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
|  		     offsetof(struct thread_vr_state, vr[32]));
|  
| +	if (MSR_TM_ACTIVE(target->thread.regs->msr))
| +		addr = &target->thread.transact_vr;
| +	else
| +		addr = &target->thread.vr_state;
| +
|  	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| -				  &target->thread.vr_state, 0,
| -				  33 * sizeof(vector128));
| +				addr, 0, 33 * sizeof(vector128));
| +
|  	if (!ret) {
|  		/*
|  		 * Copy out only the low-order word of vrsave.
| @@ -455,11 +531,14 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
|  			u32 word;
|  		} vrsave;
|  		memset(&vrsave, 0, sizeof(vrsave));
| -		vrsave.word = target->thread.vrsave;
| +		if (MSR_TM_ACTIVE(target->thread.regs->msr))
| +			vrsave.word = target->thread.transact_vrsave;
| +		else
| +			vrsave.word = target->thread.vrsave;
| +
|  		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
|  					  33 * sizeof(vector128), -1);
|  	}
| -
|  	return ret;
|  }
|  
| @@ -467,16 +546,27 @@ 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)
|  {
| +	struct thread_vr_state *addr;
|  	int ret;
|  
| -	flush_altivec_to_thread(target);
| +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
| +		flush_fp_to_thread(target);
| +		flush_altivec_to_thread(target);
| +		flush_tmregs_to_thread(target);
| +	} else {
| +		flush_altivec_to_thread(target);
| +	}
|  
|  	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
|  		     offsetof(struct thread_vr_state, vr[32]));
|  
| +	if (MSR_TM_ACTIVE(target->thread.regs->msr))
| +		addr = &target->thread.transact_vr;
| +	else
| +		addr = &target->thread.vr_state;
|  	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| -				 &target->thread.vr_state, 0,
| -				 33 * sizeof(vector128));
| +			addr, 0, 33 * sizeof(vector128));
| +
|  	if (!ret && count > 0) {
|  		/*
|  		 * We use only the first word of vrsave.
| @@ -486,13 +576,21 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
|  			u32 word;
|  		} vrsave;
|  		memset(&vrsave, 0, sizeof(vrsave));
| -		vrsave.word = target->thread.vrsave;
| +
| +		if (MSR_TM_ACTIVE(target->thread.regs->msr))
| +			vrsave.word = target->thread.transact_vrsave;
| +		else
| +			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;
| +		if (!ret) {
| +			if (MSR_TM_ACTIVE(target->thread.regs->msr))
| +				target->thread.transact_vrsave = vrsave.word;
| +			else
| +				target->thread.vrsave = vrsave.word;
| +		}
|  	}
| -
|  	return ret;
|  }
|  #endif /* CONFIG_ALTIVEC */
| @@ -613,6 +711,442 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
|  }
|  #endif /* CONFIG_SPE */
|  
| +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
| +
| +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;
| +}
| +/*
| + *  Transactional memory SPR
| + *
| + * 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;
| +
| +	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);
| +

Can we copy all the values ot a local buf and then do a single
copyout to user space ?

| +	/* TFHAR register */
| +	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +			&target->thread.tm_tfhar, 0, sizeof(u64));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar) +
| +			sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
| +
| +	/* TEXASR register */
| +	if (!ret)
| +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +			&target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr) +
| +			sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
| +
| +	/* TFIAR register */
| +	if (!ret)
| +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +			&target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar) +
| +			sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
| +
| +	/* 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));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr) +
| +			sizeof(unsigned long) + sizeof(struct pt_regs)
| +				!= offsetof(struct thread_struct, tm_tar));
| +
| +	/* 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));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
| +			+ sizeof(unsigned long) !=
| +				offsetof(struct thread_struct, tm_ppr));
| +
| +	/* 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));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
| +			sizeof(unsigned long) !=
| +				offsetof(struct thread_struct, tm_dscr));
| +
| +	/* 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;
| +}
| +
| +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;
| +
| +	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);
| +
| +	/* TFHAR register */
| +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +				&target->thread.tm_tfhar, 0, sizeof(u64));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar)
| +		+ sizeof(u64) != offsetof(struct thread_struct, tm_texasr));

A single copyin into a local buffer followed by a local assignment would
be easier to read ?

It could be easier to read if all BUILD_BUG_ON() calls are in one place
maybe near the beginning of the function or in the header file.

| +
| +	/* TEXASR register */
| +	if (!ret)
| +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +			&target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr)
| +		+ sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
| +
| +	/* TFIAR register */
| +	if (!ret)
| +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +			&target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar)
| +		+ sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
| +
| +	/* 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));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr)
| +		+ sizeof(unsigned long) + sizeof(struct pt_regs) !=
| +			offsetof(struct thread_struct, tm_tar));
| +
| +	/* 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));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
| +			+ sizeof(unsigned long) != offsetof(struct thread_struct, tm_ppr));
| +
| +	/* 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));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
| +			sizeof(unsigned long) !=
| +				offsetof(struct thread_struct, tm_dscr));
| +
| +	/* 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;
| +}
| +
| +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 Checkpointed GPR
| + *
| + * 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;
| +}
| +
| +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;
| +}
| +
| +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 Checkpointed FPR
| + *
| + * 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)
| +{
| +#ifdef CONFIG_VSX
| +	u64 buf[33];
| +	int i;
| +#endif
| +	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);
| +
| +#ifdef CONFIG_VSX
| +	/* 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);
| +
| +#else
| +	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
| +		offsetof(struct thread_fp_state, fpr[32][0]));
| +
| +	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +			&target->thread.thread_fp_state, 0, -1);
| +#endif
| +}
| +
| +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)
| +{
| +#ifdef CONFIG_VSX
| +	u64 buf[33];
| +	int i;
| +#endif
| +	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);
| +
| +#ifdef CONFIG_VSX
| +	/* 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;
| +#else
| +	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
| +		      offsetof(struct thread_fp_state, fpr[32][0]));
| +
| +	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +				&target->thread.fp_state, 0, -1);
| +#endif
| +}
| +
| +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;
| +}

All these tm_*_active() functions do the same checks - maybe they could all
call a common function ?

| +
| +/*
| + * TM Checkpointed VMX
| + *
| + * 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;
| +
| +	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);
| +
| +	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
| +		     offsetof(struct thread_vr_state, vr[32]));
| +
| +	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;
| +}
| +
| +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;
| +
| +	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);
| +
| +	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
| +		offsetof(struct thread_vr_state, vr[32]));
| +
| +	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.
| +		 */
| +		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.
| @@ -629,6 +1163,12 @@ enum powerpc_regset {
|  #ifdef CONFIG_SPE
|  	REGSET_SPE,
|  #endif
| +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
| +	REGSET_TM_SPR,		/* TM specific SPR */
| +	REGSET_TM_CGPR,		/* TM checkpointed GPR */
| +	REGSET_TM_CFPR,		/* TM checkpointed FPR */
| +	REGSET_TM_CVMX,		/* TM checkpointed VMX */
| +#endif
|  };
|  
|  static const struct user_regset native_regsets[] = {
| @@ -663,6 +1203,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 = 7,

How about adding a macro ELF_NSPRREG for the 7 special registers ?

| +		.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 = 34,

Similarly for the .n = 34

| +		.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 = {
| @@ -690,7 +1252,7 @@ static int gpr32_get(struct task_struct *target,
|  	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; 
| +			target->thread.regs->gpr[i] = NV_REG_POISON;
|  	}
|  
|  	pos /= sizeof(reg);
| @@ -803,6 +1365,157 @@ static int gpr32_set(struct task_struct *target,
|  					 (PT_TRAP + 1) * sizeof(reg), -1);
|  }
|  
| +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)
| +{
| +	const unsigned long *regs = &target->thread.ckpt_regs.gpr[0];
| +	compat_ulong_t *k = kbuf;
| +	compat_ulong_t __user *u = ubuf;
| +	compat_ulong_t reg;
| +	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);
| +
| +	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);
| +	count /= sizeof(reg);
| +
| +	if (kbuf)
| +		for (; count > 0 && pos < PT_MSR; --count)
| +			*k++ = regs[pos++];
| +	else
| +		for (; count > 0 && pos < PT_MSR; --count)
| +			if (__put_user((compat_ulong_t) regs[pos++], u++))
| +				return -EFAULT;
| +
| +	if (count > 0 && pos == PT_MSR) {
| +		reg = get_user_msr(target);
| +		if (kbuf)
| +			*k++ = reg;
| +		else if (__put_user(reg, u++))
| +			return -EFAULT;
| +		++pos;
| +		--count;
| +	}
| +
| +	if (kbuf)
| +		for (; count > 0 && pos < PT_REGS_COUNT; --count)
| +			*k++ = regs[pos++];
| +	else
| +		for (; count > 0 && pos < PT_REGS_COUNT; --count)
| +			if (__put_user((compat_ulong_t) regs[pos++], u++))
| +				return -EFAULT;
| +
| +	kbuf = k;
| +	ubuf = u;
| +	pos *= sizeof(reg);
| +	count *= sizeof(reg);
| +	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
| +					PT_REGS_COUNT * sizeof(reg), -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)
| +{
| +	unsigned long *regs = &target->thread.ckpt_regs.gpr[0];
| +	const compat_ulong_t *k = kbuf;
| +	const compat_ulong_t __user *u = ubuf;
| +	compat_ulong_t reg;
| +
| +	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);
| +
| +	if (target->thread.regs == NULL)
| +		return -EIO;
| +
| +	CHECK_FULL_REGS(target->thread.regs);
| +
| +	pos /= sizeof(reg);
| +	count /= sizeof(reg);
| +
| +	if (kbuf)
| +		for (; count > 0 && pos < PT_MSR; --count)
| +			regs[pos++] = *k++;
| +	else
| +		for (; count > 0 && pos < PT_MSR; --count) {
| +			if (__get_user(reg, u++))
| +				return -EFAULT;
| +			regs[pos++] = reg;
| +		}
| +
| +
| +	if (count > 0 && pos == PT_MSR) {
| +		if (kbuf)
| +			reg = *k++;
| +		else if (__get_user(reg, u++))
| +			return -EFAULT;
| +		set_user_msr(target, reg);
| +		++pos;
| +		--count;
| +	}
| +
| +	if (kbuf) {
| +		for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
| +			regs[pos++] = *k++;
| +		for (; count > 0 && pos < PT_TRAP; --count, ++pos)
| +			++k;
| +	} else {
| +		for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
| +			if (__get_user(reg, u++))
| +				return -EFAULT;
| +			regs[pos++] = reg;
| +		}
| +		for (; count > 0 && pos < PT_TRAP; --count, ++pos)
| +			if (__get_user(reg, u++))
| +				return -EFAULT;
| +	}
| +
| +	if (count > 0 && pos == PT_TRAP) {
| +		if (kbuf)
| +			reg = *k++;
| +		else if (__get_user(reg, u++))
| +			return -EFAULT;
| +		set_user_trap(target, reg);
| +		++pos;
| +		--count;
| +	}
| +
| +	kbuf = k;
| +	ubuf = u;
| +	pos *= sizeof(reg);
| +	count *= sizeof(reg);
| +	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
| +					 (PT_TRAP + 1) * sizeof(reg), -1);
| +}
| +
| +
|  /*
|   * These are the regset flavors matching the CONFIG_PPC32 native set.
|   */
| @@ -831,6 +1544,28 @@ 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 = 7,
| +		.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 = 34,
| +		.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 = {
| @@ -1754,7 +2489,6 @@ long arch_ptrace(struct task_struct *child, long request,
|  					     REGSET_SPE, 0, 35 * sizeof(u32),
|  					     datavp);
|  #endif
| -
|  	default:
|  		ret = ptrace_request(child, request, addr, data);
|  		break;
| -- 
| 1.7.11.7
| 
| _______________________________________________
| Linuxppc-dev mailing list
| Linuxppc-dev@lists.ozlabs.org
| https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 3/3] powerpc, ptrace: Enable support for miscellaneous registers
  2014-05-23 15:15 ` [PATCH V3 3/3] powerpc, ptrace: Enable support for miscellaneous registers Anshuman Khandual
@ 2014-08-27 21:35   ` Sukadev Bhattiprolu
  2014-10-08 16:20     ` Anshuman Khandual
  0 siblings, 1 reply; 19+ messages in thread
From: Sukadev Bhattiprolu @ 2014-08-27 21:35 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: mikey, james.hogan, avagin, Paul.Clothier, davem, peterz, palves,
	linux-kernel, oleg, dhowells, linuxppc-dev, davej, akpm, tglx


Anshuman Khandual [khandual@linux.vnet.ibm.com] wrote:
| This patch enables get and set of miscellaneous registers through ptrace
| PTRACE_GETREGSET/PTRACE_SETREGSET interface by implementing new powerpc
| specific register set REGSET_MISC support corresponding to the new ELF
| core note NT_PPC_MISC added previously in this regard.
| 
| Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
| ---
|  arch/powerpc/kernel/ptrace.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
|  1 file changed, 81 insertions(+)
| 
| diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
| index 17642ef..63b883a 100644
| --- a/arch/powerpc/kernel/ptrace.c
| +++ b/arch/powerpc/kernel/ptrace.c
| @@ -1149,6 +1149,76 @@ static int tm_cvmx_set(struct task_struct *target, const struct user_regset *reg
|  #endif	/* CONFIG_PPC_TRANSACTIONAL_MEM */
|  
|  /*
| + * Miscellaneous Registers
| + *
| + * struct {
| + * 	unsigned long dscr;
| + *	unsigned long ppr;
| + * 	unsigned long tar;
| + * };
| + */
| +static int misc_get(struct task_struct *target, const struct user_regset *regset,
| +		   unsigned int pos, unsigned int count,
| +		   void *kbuf, void __user *ubuf)
| +{
| +	int ret;
| +
| +	/* DSCR register */
| +	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +					&target->thread.dscr, 0,
| +					sizeof(unsigned long));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned long) +
| +				sizeof(unsigned long) != offsetof(struct thread_struct, ppr));


I see these in  arch/powerpc/include/asm/processor.h

#ifdef CONFIG_PPC64
        unsigned long   dscr;
        int             dscr_inherit;
        unsigned long   ppr;    /* used to save/restore SMT priority */
#endif

where there is an 'int' between ppr and dscr. So, should one of
the above sizeof(unsigned long) be changed to sizeof(int) ?

Also, since we use offsetof(struct thread_struct, field) heavily, a
macro local to the file, may simplify the code.

#define	TSO(f)	(offsetof(struct thread_struct, f))

| +
| +	/* PPR register */
| +	if (!ret)
| +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +					  &target->thread.ppr, sizeof(unsigned long),
| +					  2 * sizeof(unsigned long));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
| +						!= offsetof(struct thread_struct, tar));
| +	/* TAR register */
| +	if (!ret)
| +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +					  &target->thread.tar, 2 * sizeof(unsigned long),
| +					  3 * sizeof(unsigned long));
| +	return ret;
| +}
| +
| +static int misc_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;
| +
| +	/* DSCR register */
| +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +					&target->thread.dscr, 0,
| +					sizeof(unsigned long));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned long) +
| +			sizeof(unsigned long) != offsetof(struct thread_struct, ppr));
| +
| +	/* PPR register */
| +	if (!ret)
| +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +						&target->thread.ppr, sizeof(unsigned long),
| +						2 * sizeof(unsigned long));
| +
| +	BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
| +						!= offsetof(struct thread_struct, tar));
| +
| +	/* TAR register */
| +	if (!ret)
| +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +						&target->thread.tar, 2 * sizeof(unsigned long),
| +						3 * sizeof(unsigned long));
| +	return ret;
| +}
| +
| +/*
|   * These are our native regset flavors.
|   */
|  enum powerpc_regset {
| @@ -1169,6 +1239,7 @@ enum powerpc_regset {
|  	REGSET_TM_CFPR,		/* TM checkpointed FPR */
|  	REGSET_TM_CVMX,		/* TM checkpointed VMX */
|  #endif
| +	REGSET_MISC		/* Miscellaneous */
|  };
|  
|  static const struct user_regset native_regsets[] = {
| @@ -1225,6 +1296,11 @@ static const struct user_regset native_regsets[] = {
|  		.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
|  	},
|  #endif
| +	[REGSET_MISC] = {
| +		.core_note_type = NT_PPC_MISC, .n = 3,
| +		.size = sizeof(u64), .align = sizeof(u64),
| +		.get = misc_get, .set = misc_set
| +	},
|  };
|  
|  static const struct user_regset_view user_ppc_native_view = {
| @@ -1566,6 +1642,11 @@ static const struct user_regset compat_regsets[] = {
|  		.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
|  	},
|  #endif
| +	[REGSET_MISC] = {
| +		.core_note_type = NT_PPC_MISC, .n = 3,
| +		.size = sizeof(u64), .align = sizeof(u64),
| +		.get = misc_get, .set = misc_set
| +	},

Since the .n = 3 is used more than once, how about a macro for the
number of misc registers ?

|  };
|  
|  static const struct user_regset_view user_ppc_compat_view = {
| -- 
| 1.7.11.7
| 
| _______________________________________________
| Linuxppc-dev mailing list
| Linuxppc-dev@lists.ozlabs.org
| https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
  2014-05-23 15:15 [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
                   ` (4 preceding siblings ...)
  2014-07-24  6:52 ` Sam Bobroff
@ 2014-09-11  6:14 ` Anshuman Khandual
  5 siblings, 0 replies; 19+ messages in thread
From: Anshuman Khandual @ 2014-09-11  6:14 UTC (permalink / raw)
  To: linux-kernel, linuxppc-dev, peterz, akpm, tglx
  Cc: mikey, james.hogan, avagin, Paul.Clothier, palves, oleg,
	dhowells, davej, Sukadev Bhattiprolu, davem, Sam Bobroff

On 05/23/2014 08:45 PM, Anshuman Khandual wrote:
> 	This patch series adds five new ELF core note sections which can be
> used with existing ptrace request PTRACE_GETREGSET/SETREGSET for accessing
> various transactional memory and miscellaneous register sets on PowerPC
> platform. Please find a test program exploiting these new ELF core note
> types on a POWER8 system.
> 
> RFC: https://lkml.org/lkml/2014/4/1/292
> V1:  https://lkml.org/lkml/2014/4/2/43
> V2:  https://lkml.org/lkml/2014/5/5/88
> 
> Changes in V3
> =============
> (1) Added two new error paths in every TM related get/set functions when regset
>     support is not present on the system (ENODEV) or when the process does not
>     have any transaction active (ENODATA) in the context
> 
> (2) Installed the active hooks for all the newly added regset core note types
> 
> Changes in V2
> =============
> (1) Removed all the power specific ptrace requests corresponding to new NT_PPC_*
>     elf core note types. Now all the register sets can be accessed from ptrace
>     through PTRACE_GETREGSET/PTRACE_SETREGSET using the individual NT_PPC* core
>     note type instead
> (2) Fixed couple of attribute values for REGSET_TM_CGPR register set
> (3) Renamed flush_tmreg_to_thread as flush_tmregs_to_thread
> (4) Fixed 32 bit checkpointed GPR support
> (5) Changed commit messages accordingly
> 
> Outstanding Issues
> ==================
> (1) Running DSCR register value inside a transaction does not seem to be saved
>     at thread.dscr when the process stops for ptrace examination.

Hey Sam and Suka,

Thanks for reviewing this patch series. I was busy with some other work
for last couple of months. Went through your comments, will get back to
this patch series in some time and work on the comments.

Thanks again.

Regards
Anshuman

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
  2014-07-24  6:52 ` Sam Bobroff
@ 2014-10-07 12:35   ` Anshuman Khandual
  0 siblings, 0 replies; 19+ messages in thread
From: Anshuman Khandual @ 2014-10-07 12:35 UTC (permalink / raw)
  To: Sam Bobroff, linux-kernel, linuxppc-dev, peterz, akpm, tglx
  Cc: mikey, james.hogan, avagin, Paul.Clothier, palves, oleg,
	dhowells, davej, davem

On 07/24/2014 12:22 PM, Sam Bobroff wrote:
>> Outstanding Issues
>> ==================
>> (1) Running DSCR register value inside a transaction does not seem to be saved
>>     at thread.dscr when the process stops for ptrace examination.
> 
> Since this is fixed by 96d016108640bc2b7fb0ee800737f80923847294, which
> is already upstream, you might want to rebase and re-test. It should
> pass and then you can remove the outstanding issues :-)

Sure will do that.

> 
>>     
>> Test programs
> 
> program
> 
> When I posted the patch I mentioned above, I was asked to move the test
> code into the powerpc kernel selftests so you may want to do this too.

Yes, I will add these ptrace related tests as tm/tm-ptrace.c test case.

> 
> Also, your test program covers everything mine did and more so you might
> want to remove mine if you do add this to the selftests.

The new one will be more ptrace specific, so wont remove yours which tests
the context saved DSCR value.

> 
>> =============
>> #include <unistd.h>
>> #include <stdlib.h>
>> #include <string.h>
>> #include <malloc.h>
>> #include <errno.h>
>> #include <sys/ptrace.h>
>> #include <sys/uio.h>
>> #include <sys/types.h>
>> #include <sys/signal.h>
>> #include <sys/user.h>
> 
> You should include sys/wait.h for waitpid().

Will do.

> status, i and flags are all unused.

Will remove them.

>> 			else
>> 				printf("DSCR FAILED\n");
>>
>> 			/* TM checkpointed GPR */
>> 			iov.iov_base = (struct pt_regs *) malloc(sizeof(struct pt_regs));;
>> 			iov.iov_len = sizeof(struct pt_regs);
>> 			ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov);
>> 			if (ret == -1) {
>> 				printf("PTRACE_GETREGSET: NT_PPC_TM_CGPR failed: %s\n", strerror(errno));
>> 				exit(-1);
>> 			}
>>
>> 			if (iov.iov_len != sizeof(struct pt_regs)) {
>> 				printf("NT_PPC_TM_CGPR: Length returned is wrong\n");
>> 				exit(-1);
>> 			}
>>
>> 			pregs1 = iov.iov_base;
>> 			printf("-------TM checkpointed GPR-----\n");
>> 			printf("TM CH GPR[1]: %x\n", pregs1->gpr[1]);
>> 			printf("TM CH GPR[2]: %x\n", pregs1->gpr[2]);
>> 			printf("TM CH NIP: %x\n", pregs1->nip);
>> 			printf("TM CH LINK: %x\n", pregs1->link);
>> 			printf("TM CH CCR: %x\n", pregs1->ccr);
> 
> I get a compiler warning for these printfs: they should be "%lx".

Okay.

> 
>>
>> 			if (pregs1->gpr[1] == VAL1)
>> 				printf("GPR[1] PASSED\n");
>> 			else
>> 				printf("GPR[1] FAILED\n");
>>
>> 			if (pregs1->gpr[2] == VAL2)
>> 				printf("GPR[2] PASSED\n");
>> 			else
>> 				printf("GPR[2] FAILED\n");
>>
>> 			/* TM running GPR */
>> 			ret = ptrace(PTRACE_GETREGS, child, NULL, pregs2);
>> 			if (ret == -1) {
>> 				printf("PTRACE_GETREGS fail: %s\n", strerror(errno));
>> 				exit(-1);
>> 			}
>>
>> 			printf("-------TM running GPR-----\n");
>> 			printf("TM RN GPR[1]: %x\n", pregs2->gpr[1]);
>> 			printf("TM RN GPR[2]: %x\n", pregs2->gpr[2]);
>> 			printf("TM RN NIP: %x\n", pregs2->nip);
>> 			printf("TM RN LINK: %x\n", pregs2->link);
>> 			printf("TM RN CCR: %x\n", pregs2->ccr);
> 
> Same as above, I get warnings and they should be "%lx".

Okay. Will fix them.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 3/3] powerpc, ptrace: Enable support for miscellaneous registers
  2014-08-27 21:35   ` Sukadev Bhattiprolu
@ 2014-10-08 16:20     ` Anshuman Khandual
  2014-10-08 17:16       ` Sukadev Bhattiprolu
  0 siblings, 1 reply; 19+ messages in thread
From: Anshuman Khandual @ 2014-10-08 16:20 UTC (permalink / raw)
  To: Sukadev Bhattiprolu
  Cc: mikey, james.hogan, avagin, Paul.Clothier, davem, peterz, palves,
	linux-kernel, oleg, dhowells, linuxppc-dev, davej, akpm, tglx

On 08/28/2014 03:05 AM, Sukadev Bhattiprolu wrote:
> 
> Anshuman Khandual [khandual@linux.vnet.ibm.com] wrote:
> | This patch enables get and set of miscellaneous registers through ptrace
> | PTRACE_GETREGSET/PTRACE_SETREGSET interface by implementing new powerpc
> | specific register set REGSET_MISC support corresponding to the new ELF
> | core note NT_PPC_MISC added previously in this regard.
> | 
> | Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
> | ---
> |  arch/powerpc/kernel/ptrace.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
> |  1 file changed, 81 insertions(+)
> | 
> | diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
> | index 17642ef..63b883a 100644
> | --- a/arch/powerpc/kernel/ptrace.c
> | +++ b/arch/powerpc/kernel/ptrace.c
> | @@ -1149,6 +1149,76 @@ static int tm_cvmx_set(struct task_struct *target, const struct user_regset *reg
> |  #endif	/* CONFIG_PPC_TRANSACTIONAL_MEM */
> |  
> |  /*
> | + * Miscellaneous Registers
> | + *
> | + * struct {
> | + * 	unsigned long dscr;
> | + *	unsigned long ppr;
> | + * 	unsigned long tar;
> | + * };
> | + */
> | +static int misc_get(struct task_struct *target, const struct user_regset *regset,
> | +		   unsigned int pos, unsigned int count,
> | +		   void *kbuf, void __user *ubuf)
> | +{
> | +	int ret;
> | +
> | +	/* DSCR register */
> | +	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> | +					&target->thread.dscr, 0,
> | +					sizeof(unsigned long));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned long) +
> | +				sizeof(unsigned long) != offsetof(struct thread_struct, ppr));
> 
> 
> I see these in  arch/powerpc/include/asm/processor.h
> 
> #ifdef CONFIG_PPC64
>         unsigned long   dscr;
>         int             dscr_inherit;
>         unsigned long   ppr;    /* used to save/restore SMT priority */
> #endif
> 
> where there is an 'int' between ppr and dscr. So, should one of
> the above sizeof(unsigned long) be changed to sizeof(int) ?

Right, I understand that but strangely I get this compile time error
when it is changed to sizeof(int).

 error: call to ‘__compiletime_assert_1350’ declared with attribute error:
  BUILD_BUG_ON failed: TSO(dscr) + sizeof(unsigned long) + sizeof(int) != TSO(ppr)
  BUILD_BUG_ON(TSO(dscr) + sizeof(unsigned long) + sizeof(int) != TSO(ppr));

may be I am missing something here.

> 
> Also, since we use offsetof(struct thread_struct, field) heavily, a
> macro local to the file, may simplify the code.

Right, will do that.

> #define	TSO(f)	(offsetof(struct thread_struct, f))
> 
> | +
> | +	/* PPR register */
> | +	if (!ret)
> | +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> | +					  &target->thread.ppr, sizeof(unsigned long),
> | +					  2 * sizeof(unsigned long));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
> | +						!= offsetof(struct thread_struct, tar));
> | +	/* TAR register */
> | +	if (!ret)
> | +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> | +					  &target->thread.tar, 2 * sizeof(unsigned long),
> | +					  3 * sizeof(unsigned long));
> | +	return ret;
> | +}
> | +
> | +static int misc_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;
> | +
> | +	/* DSCR register */
> | +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | +					&target->thread.dscr, 0,
> | +					sizeof(unsigned long));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned long) +
> | +			sizeof(unsigned long) != offsetof(struct thread_struct, ppr));
> | +
> | +	/* PPR register */
> | +	if (!ret)
> | +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | +						&target->thread.ppr, sizeof(unsigned long),
> | +						2 * sizeof(unsigned long));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
> | +						!= offsetof(struct thread_struct, tar));
> | +
> | +	/* TAR register */
> | +	if (!ret)
> | +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | +						&target->thread.tar, 2 * sizeof(unsigned long),
> | +						3 * sizeof(unsigned long));
> | +	return ret;
> | +}
> | +
> | +/*
> |   * These are our native regset flavors.
> |   */
> |  enum powerpc_regset {
> | @@ -1169,6 +1239,7 @@ enum powerpc_regset {
> |  	REGSET_TM_CFPR,		/* TM checkpointed FPR */
> |  	REGSET_TM_CVMX,		/* TM checkpointed VMX */
> |  #endif
> | +	REGSET_MISC		/* Miscellaneous */
> |  };
> |  
> |  static const struct user_regset native_regsets[] = {
> | @@ -1225,6 +1296,11 @@ static const struct user_regset native_regsets[] = {
> |  		.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
> |  	},
> |  #endif
> | +	[REGSET_MISC] = {
> | +		.core_note_type = NT_PPC_MISC, .n = 3,
> | +		.size = sizeof(u64), .align = sizeof(u64),
> | +		.get = misc_get, .set = misc_set
> | +	},
> |  };
> |  
> |  static const struct user_regset_view user_ppc_native_view = {
> | @@ -1566,6 +1642,11 @@ static const struct user_regset compat_regsets[] = {
> |  		.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
> |  	},
> |  #endif
> | +	[REGSET_MISC] = {
> | +		.core_note_type = NT_PPC_MISC, .n = 3,
> | +		.size = sizeof(u64), .align = sizeof(u64),
> | +		.get = misc_get, .set = misc_set
> | +	},
> 
> Since the .n = 3 is used more than once, how about a macro for the
> number of misc registers ?

Will add it as well. Thanks !

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 3/3] powerpc, ptrace: Enable support for miscellaneous registers
  2014-10-08 16:20     ` Anshuman Khandual
@ 2014-10-08 17:16       ` Sukadev Bhattiprolu
  0 siblings, 0 replies; 19+ messages in thread
From: Sukadev Bhattiprolu @ 2014-10-08 17:16 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: mikey, james.hogan, avagin, Paul.Clothier, davem, peterz, palves,
	linux-kernel, oleg, dhowells, linuxppc-dev, davej, akpm, tglx

Anshuman Khandual [khandual@linux.vnet.ibm.com] wrote:
| On 08/28/2014 03:05 AM, Sukadev Bhattiprolu wrote:
| >=20
| > I see these in  arch/powerpc/include/asm/processor.h
| >=20
| > #ifdef CONFIG_PPC64
| >         unsigned long   dscr;
| >         int             dscr_inherit;
| >         unsigned long   ppr;    /* used to save/restore SMT priority */
| > #endif
| >=20
| > where there is an 'int' between ppr and dscr. So, should one of
| > the above sizeof(unsigned long) be changed to sizeof(int) ?
|=20
| Right, I understand that but strangely I get this compile time error
| when it is changed to sizeof(int).
|=20
|  error: call to =E2=80=98__compiletime_assert_1350=E2=80=99 declared with=
 attribute error:
|   BUILD_BUG_ON failed: TSO(dscr) + sizeof(unsigned long) + sizeof(int) !=
=3D TSO(ppr)
|   BUILD_BUG_ON(TSO(dscr) + sizeof(unsigned long) + sizeof(int) !=3D TSO(p=
pr));
|=20
| may be I am missing something here.

I guess there is a 4-byte padding after dscr_inherit. We could make that
explicit by adding a field or just go with the sizeof(unsigned long).

Thanks,

Sukadev

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 2/3] powerpc, ptrace: Enable support for transactional memory register sets
  2014-08-27 21:35   ` Sukadev Bhattiprolu
@ 2014-10-09  5:04     ` Anshuman Khandual
  0 siblings, 0 replies; 19+ messages in thread
From: Anshuman Khandual @ 2014-10-09  5:04 UTC (permalink / raw)
  To: Sukadev Bhattiprolu
  Cc: mikey, james.hogan, avagin, Paul.Clothier, davem, peterz, palves,
	linux-kernel, oleg, dhowells, linuxppc-dev, davej, akpm, tglx

On 08/28/2014 03:05 AM, Sukadev Bhattiprolu wrote:
> Anshuman Khandual [khandual@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 <khandual@linux.vnet.ibm.com>
> | ---
> |  arch/powerpc/include/asm/switch_to.h |   8 +
> |  arch/powerpc/kernel/process.c        |  24 ++
> |  arch/powerpc/kernel/ptrace.c         | 792 +++++++++++++++++++++++++++++++++--
> |  3 files changed, 795 insertions(+), 29 deletions(-)
> | 
> | diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
> | index 0e83e7d..2737f46 100644
> | --- a/arch/powerpc/include/asm/switch_to.h
> | +++ b/arch/powerpc/include/asm/switch_to.h
> | @@ -80,6 +80,14 @@ static inline void flush_spe_to_thread(struct task_struct *t)
> |  }
> |  #endif
> |  
> | +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> | +extern void flush_tmregs_to_thread(struct task_struct *);
> | +#else
> | +static inline void flush_tmregs_to_thread(struct task_struct *t)
> | +{
> | +}
> | +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
> | +
> |  static inline void clear_task_ebb(struct task_struct *t)
> |  {
> |  #ifdef CONFIG_PPC_BOOK3S_64
> | diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
> | index 31d0215..e247898 100644
> | --- a/arch/powerpc/kernel/process.c
> | +++ b/arch/powerpc/kernel/process.c
> | @@ -695,6 +695,30 @@ static inline void __switch_to_tm(struct task_struct *prev)
> |  	}
> |  }
> |  
> | +void flush_tmregs_to_thread(struct task_struct *tsk)
> | +{
> | +	/*
> | +	 * If task is not current, it should have been flushed
> | +	 * already to it's thread_struct during __switch_to().
> | +	 */
> | +	if (tsk != current)
> | +		return;
> | +
> | +	preempt_disable();
> | +	if (tsk->thread.regs) {
> | +		/*
> | +		 * If we are still current, the TM state need to
> | +		 * be flushed to thread_struct as it will be still
> | +		 * present in the current cpu.
> | +		 */
> | +		if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
> | +			__switch_to_tm(tsk);
> | +			tm_recheckpoint_new_task(tsk);
> | +		}
> | +	}
> | +	preempt_enable();
> | +}
> | +
> |  /*
> |   * This is called if we are on the way out to userspace and the
> |   * TIF_RESTORE_TM flag is set.  It checks if we need to reload
> | diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
> | index 2e3d2bf..17642ef 100644
> | --- a/arch/powerpc/kernel/ptrace.c
> | +++ b/arch/powerpc/kernel/ptrace.c
> | @@ -357,6 +357,17 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
> |  	return ret;
> |  }
> |  
> | +/*
> | + * When any transaction is active, "thread_struct->transact_fp" holds
> | + * the current running value of all FPR registers and "thread_struct->
> | + * fp_state" holds the last checkpointed FPR registers state for the
> | + * current transaction.
> | + *
> | + * struct data {
> | + * 	u64	fpr[32];
> | + * 	u64	fpscr;
> | + * };
> | + */
> 
> Maybe a reference to 'struct thread_fp_state' in the comments will help ?

Okay, will try to add.

> 
> 
> |  static int fpr_get(struct task_struct *target, const struct user_regset *regset,
> |  		   unsigned int pos, unsigned int count,
> |  		   void *kbuf, void __user *ubuf)
> | @@ -365,21 +376,41 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
> |  	u64 buf[33];
> |  	int i;
> |  #endif
> | -	flush_fp_to_thread(target);
> | +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> | +		flush_fp_to_thread(target);
> | +		flush_altivec_to_thread(target);
> | +		flush_tmregs_to_thread(target);
> | +	} else {
> | +		flush_fp_to_thread(target);
> | +	}
> 
> flush_fp_to_thread(target) is uncondtional - so could be outside
> the if and else blocks ?

yes

> 
> |  
> |  #ifdef CONFIG_VSX
> |  	/* 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;
> | +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> | +		for (i = 0; i < 32 ; i++)
> | +			buf[i] = target->thread.TS_TRANS_FPR(i);
> | +		buf[32] = target->thread.transact_fp.fpscr;
> | +	} else {
> | +		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);
> |  
> |  #else
> | -	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> | -		     offsetof(struct thread_fp_state, fpr[32][0]));
> | +	if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
> | +		BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
> | +				offsetof(struct transact_fp, fpr[32][0]));
> 
> Is MSR_TM_ACTIVE() a run time check or compile time ?

Its a run time check.

> ie is there a reason to move the compile time check into the if block ?

Have cleaned up all of these.

> 
> |  
> | -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> | +		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> | +				   &target->thread.transact_fp, 0, -1);
> | +	} esle {
> | +		BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> | +			     offsetof(struct thread_fp_state, fpr[32][0]));
> | +
> | +		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> |  				   &target->thread.fp_state, 0, -1);
> | +	}
> |  #endif
> |  }
> |  
> | @@ -391,23 +422,44 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
> |  	u64 buf[33];
> |  	int i;
> |  #endif
> | -	flush_fp_to_thread(target);
> | +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> | +		flush_fp_to_thread(target);
> | +		flush_altivec_to_thread(target);
> | +		flush_tmregs_to_thread(target);
> | +	} else {
> | +		flush_fp_to_thread(target);
> | +	}
> |  
> 
> As mentioned above, flush_fp_to_thread() could be outside the if block.

sure

> |  #ifdef CONFIG_VSX
> |  	/* 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];
> | +	for (i = 0; i < 32 ; i++) {
> | +		if (MSR_TM_ACTIVE(target->thread.regs->msr))
> | +			target->thread.TS_TRANS_FPR(i) = buf[i];
> | +		else
> | +			target->thread.TS_FPR(i) = buf[i];
> | +	}
> | +	if (MSR_TM_ACTIVE(target->thread.regs->msr))
> | +		target->thread.transact_fp.fpscr = buf[32];
> | +	else
> | +		target->thread.fp_state.fpscr = buf[32];
> 
> I think this code is easier to read than the similar code above
> in fpr_get() where you have the 'for' loop in both if and else blocks.

Have done some modifications here.

> 
> |  	return 0;
> |  #else
> | -	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> | -		     offsetof(struct thread_fp_state, fpr[32][0]));
> | +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> | +		BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
> | +			     offsetof(struct transact_fp, fpr[32][0]));
> |  
> | -	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | -				  &target->thread.fp_state, 0, -1);
> | +		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | +					  &target->thread.transact_fp, 0, -1);
> | +	} else {
> | +		BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> | +			     offsetof(struct thread_fp_state, fpr[32][0]));
> | +
> | +		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | +				&target->thread.fp_state, 0, -1);
> | +	}
> |  #endif
> |  }
> |  
> | @@ -432,20 +484,44 @@ static int vr_active(struct task_struct *target,
> |  	return target->thread.used_vr ? regset->n : 0;
> |  }
> |  
> | +/*
> | + * When any transaction is active, "thread_struct->transact_vr" holds
> | + * the current running value of all VMX registers and "thread_struct->
> | + * vr_state" holds the last checkpointed value of VMX registers for the
> | + * current transaction.
> | + *
> | + * 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)
> |  {
> |  	int ret;
> | +	struct thread_vr_state *addr;
> |  
> | -	flush_altivec_to_thread(target);
> | +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> | +		flush_fp_to_thread(target);
> | +		flush_altivec_to_thread(target);
> 
> Is order of flush_fp_to_thread() and flush_altivec_to_thread()
> significant or can we call flush_altivec_to_thread() unconditionally
> outside the if block ?

We can move it outside the if block.

> | +		flush_tmregs_to_thread(target);
> | +	} else {
> | +		flush_altivec_to_thread(target);
> | +	}
> |  
> |  	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
> |  		     offsetof(struct thread_vr_state, vr[32]));
> |  
> | +	if (MSR_TM_ACTIVE(target->thread.regs->msr))
> | +		addr = &target->thread.transact_vr;
> | +	else
> | +		addr = &target->thread.vr_state;
> | +
> |  	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> | -				  &target->thread.vr_state, 0,
> | -				  33 * sizeof(vector128));
> | +				addr, 0, 33 * sizeof(vector128));
> | +
> |  	if (!ret) {
> |  		/*
> |  		 * Copy out only the low-order word of vrsave.
> | @@ -455,11 +531,14 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
> |  			u32 word;
> |  		} vrsave;
> |  		memset(&vrsave, 0, sizeof(vrsave));
> | -		vrsave.word = target->thread.vrsave;
> | +		if (MSR_TM_ACTIVE(target->thread.regs->msr))
> | +			vrsave.word = target->thread.transact_vrsave;
> | +		else
> | +			vrsave.word = target->thread.vrsave;
> | +
> |  		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
> |  					  33 * sizeof(vector128), -1);
> |  	}
> | -
> |  	return ret;
> |  }
> |  
> | @@ -467,16 +546,27 @@ 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)
> |  {
> | +	struct thread_vr_state *addr;
> |  	int ret;
> |  
> | -	flush_altivec_to_thread(target);
> | +	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
> | +		flush_fp_to_thread(target);
> | +		flush_altivec_to_thread(target);
> | +		flush_tmregs_to_thread(target);
> | +	} else {
> | +		flush_altivec_to_thread(target);
> | +	}
> |  
> |  	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
> |  		     offsetof(struct thread_vr_state, vr[32]));
> |  
> | +	if (MSR_TM_ACTIVE(target->thread.regs->msr))
> | +		addr = &target->thread.transact_vr;
> | +	else
> | +		addr = &target->thread.vr_state;
> |  	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | -				 &target->thread.vr_state, 0,
> | -				 33 * sizeof(vector128));
> | +			addr, 0, 33 * sizeof(vector128));
> | +
> |  	if (!ret && count > 0) {
> |  		/*
> |  		 * We use only the first word of vrsave.
> | @@ -486,13 +576,21 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
> |  			u32 word;
> |  		} vrsave;
> |  		memset(&vrsave, 0, sizeof(vrsave));
> | -		vrsave.word = target->thread.vrsave;
> | +
> | +		if (MSR_TM_ACTIVE(target->thread.regs->msr))
> | +			vrsave.word = target->thread.transact_vrsave;
> | +		else
> | +			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;
> | +		if (!ret) {
> | +			if (MSR_TM_ACTIVE(target->thread.regs->msr))
> | +				target->thread.transact_vrsave = vrsave.word;
> | +			else
> | +				target->thread.vrsave = vrsave.word;
> | +		}
> |  	}
> | -
> |  	return ret;
> |  }
> |  #endif /* CONFIG_ALTIVEC */
> | @@ -613,6 +711,442 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
> |  }
> |  #endif /* CONFIG_SPE */
> |  
> | +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> | +
> | +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;
> | +}
> | +/*
> | + *  Transactional memory SPR
> | + *
> | + * 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;
> | +
> | +	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);
> | +
> 
> Can we copy all the values ot a local buf and then do a single
> copyout to user space ?

In the present code, it can copy out registers to user space
till one attempt fails. Just one copy out to user space will
not give this opportunity. Either all of them go or none of
them goes.

> 
> | +	/* TFHAR register */
> | +	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> | +			&target->thread.tm_tfhar, 0, sizeof(u64));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar) +
> | +			sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
> | +
> | +	/* TEXASR register */
> | +	if (!ret)
> | +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> | +			&target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr) +
> | +			sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
> | +
> | +	/* TFIAR register */
> | +	if (!ret)
> | +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> | +			&target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar) +
> | +			sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
> | +
> | +	/* 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));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr) +
> | +			sizeof(unsigned long) + sizeof(struct pt_regs)
> | +				!= offsetof(struct thread_struct, tm_tar));
> | +
> | +	/* 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));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
> | +			+ sizeof(unsigned long) !=
> | +				offsetof(struct thread_struct, tm_ppr));
> | +
> | +	/* 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));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
> | +			sizeof(unsigned long) !=
> | +				offsetof(struct thread_struct, tm_dscr));
> | +
> | +	/* 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;
> | +}
> | +
> | +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;
> | +
> | +	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);
> | +
> | +	/* TFHAR register */
> | +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | +				&target->thread.tm_tfhar, 0, sizeof(u64));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar)
> | +		+ sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
> 
> A single copyin into a local buffer followed by a local assignment would
> be easier to read ?

I guess the same logic applies here as well.

> 
> It could be easier to read if all BUILD_BUG_ON() calls are in one place
> maybe near the beginning of the function or in the header file.

Will move them to the beginning of the function.
> 
> | +
> | +	/* TEXASR register */
> | +	if (!ret)
> | +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | +			&target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr)
> | +		+ sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
> | +
> | +	/* TFIAR register */
> | +	if (!ret)
> | +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | +			&target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar)
> | +		+ sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
> | +
> | +	/* 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));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr)
> | +		+ sizeof(unsigned long) + sizeof(struct pt_regs) !=
> | +			offsetof(struct thread_struct, tm_tar));
> | +
> | +	/* 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));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
> | +			+ sizeof(unsigned long) != offsetof(struct thread_struct, tm_ppr));
> | +
> | +	/* 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));
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
> | +			sizeof(unsigned long) !=
> | +				offsetof(struct thread_struct, tm_dscr));
> | +
> | +	/* 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;
> | +}
> | +
> | +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 Checkpointed GPR
> | + *
> | + * 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;
> | +}
> | +
> | +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;
> | +}
> | +
> | +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 Checkpointed FPR
> | + *
> | + * 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)
> | +{
> | +#ifdef CONFIG_VSX
> | +	u64 buf[33];
> | +	int i;
> | +#endif
> | +	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);
> | +
> | +#ifdef CONFIG_VSX
> | +	/* 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);
> | +
> | +#else
> | +	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> | +		offsetof(struct thread_fp_state, fpr[32][0]));
> | +
> | +	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> | +			&target->thread.thread_fp_state, 0, -1);
> | +#endif
> | +}
> | +
> | +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)
> | +{
> | +#ifdef CONFIG_VSX
> | +	u64 buf[33];
> | +	int i;
> | +#endif
> | +	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);
> | +
> | +#ifdef CONFIG_VSX
> | +	/* 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;
> | +#else
> | +	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
> | +		      offsetof(struct thread_fp_state, fpr[32][0]));
> | +
> | +	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
> | +				&target->thread.fp_state, 0, -1);
> | +#endif
> | +}
> | +
> | +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;
> | +}
> 
> All these tm_*_active() functions do the same checks - maybe they could all
> call a common function ?

Will look into it.

> 
> | +
> | +/*
> | + * TM Checkpointed VMX
> | + *
> | + * 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;
> | +
> | +	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);
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
> | +		     offsetof(struct thread_vr_state, vr[32]));
> | +
> | +	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;
> | +}
> | +
> | +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;
> | +
> | +	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);
> | +
> | +	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
> | +		offsetof(struct thread_vr_state, vr[32]));
> | +
> | +	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.
> | +		 */
> | +		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.
> | @@ -629,6 +1163,12 @@ enum powerpc_regset {
> |  #ifdef CONFIG_SPE
> |  	REGSET_SPE,
> |  #endif
> | +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> | +	REGSET_TM_SPR,		/* TM specific SPR */
> | +	REGSET_TM_CGPR,		/* TM checkpointed GPR */
> | +	REGSET_TM_CFPR,		/* TM checkpointed FPR */
> | +	REGSET_TM_CVMX,		/* TM checkpointed VMX */
> | +#endif
> |  };
> |  
> |  static const struct user_regset native_regsets[] = {
> | @@ -663,6 +1203,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 = 7,
> 
> How about adding a macro ELF_NSPRREG for the 7 special registers ?

Will do that.

> 
> | +		.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 = 34,
> 
> Similarly for the .n = 34

Sure.

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2014-10-09  5:04 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-23 15:15 [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
2014-05-23 15:15 ` [PATCH V3 1/3] elf: Add some new PowerPC specifc note sections Anshuman Khandual
2014-05-23 15:15 ` [PATCH V3 2/3] powerpc, ptrace: Enable support for transactional memory register sets Anshuman Khandual
2014-07-24  6:56   ` Sam Bobroff
2014-08-27 21:35   ` Sukadev Bhattiprolu
2014-10-09  5:04     ` Anshuman Khandual
2014-05-23 15:15 ` [PATCH V3 3/3] powerpc, ptrace: Enable support for miscellaneous registers Anshuman Khandual
2014-08-27 21:35   ` Sukadev Bhattiprolu
2014-10-08 16:20     ` Anshuman Khandual
2014-10-08 17:16       ` Sukadev Bhattiprolu
2014-06-12  9:09 ` [PATCH V3 0/3] Add new PowerPC specific ELF core notes Anshuman Khandual
2014-07-17 10:27   ` Anshuman Khandual
2014-07-17 11:09     ` Benjamin Herrenschmidt
2014-07-17 11:14       ` Michael Neuling
2014-07-17 23:23         ` Sam Bobroff
2014-07-18  8:13           ` Anshuman Khandual
2014-07-24  6:52 ` Sam Bobroff
2014-10-07 12:35   ` Anshuman Khandual
2014-09-11  6:14 ` Anshuman Khandual

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).