Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d3918f7 authored by Anshuman Khandual's avatar Anshuman Khandual Committed by Michael Ellerman
Browse files

powerpc/ptrace: Enable support for NT_PPC_CVSX



This patch enables support for TM checkpointed VSX register
set ELF core note NT_PPC_CVSX based ptrace requests through
PTRACE_GETREGSET, PTRACE_SETREGSET calls. This is achieved
through adding a register set REGSET_CVSX in powerpc
corresponding to the ELF core note section added. It
implements the get, set and active functions for this new
register set added.

Signed-off-by: default avatarAnshuman Khandual <khandual@linux.vnet.ibm.com>
Signed-off-by: default avatarSimon Guo <wei.guo.simon@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 8c13f599
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@
#define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
#define ELF_NFPREG	33	/* includes fpscr */
#define ELF_NVMX	34	/* includes all vector registers */
#define ELF_NVSX	32	/* includes all VSX registers */

typedef unsigned long elf_greg_t64;
typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG];
+129 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ struct pt_regs_offset {
#define REG_OFFSET_END {.name = NULL, .offset = 0}

#define TVSO(f)	(offsetof(struct thread_vr_state, f))
#define TFSO(f)	(offsetof(struct thread_fp_state, f))

static const struct pt_regs_offset regoffset_table[] = {
	GPR_OFFSET_NAME(0),
@@ -1294,6 +1295,123 @@ static int tm_cvmx_set(struct task_struct *target,

	return ret;
}

/**
 * tm_cvsx_active - get active number of registers in CVSX
 * @target:	The target task.
 * @regset:	The user regset structure.
 *
 * This function checks for the active number of available
 * regisers in transaction checkpointed VSX category.
 */
static int tm_cvsx_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;

	flush_vsx_to_thread(target);
	return target->thread.used_vsr ? regset->n : 0;
}

/**
 * tm_cvsx_get - get CVSX registers
 * @target:	The target task.
 * @regset:	The user regset structure.
 * @pos:	The buffer position.
 * @count:	Number of bytes to copy.
 * @kbuf:	Kernel buffer to copy from.
 * @ubuf:	User buffer to copy into.
 *
 * This function gets in transaction checkpointed VSX registers.
 *
 * When the transaction is active 'fp_state' holds the checkpointed
 * values for the current transaction to fall back on if it aborts
 * in between. This function gets those checkpointed VSX registers.
 * The userspace interface buffer layout is as follows.
 *
 * struct data {
 *	u64	vsx[32];
 *};
 */
static int tm_cvsx_get(struct task_struct *target,
			const struct user_regset *regset,
			unsigned int pos, unsigned int count,
			void *kbuf, void __user *ubuf)
{
	u64 buf[32];
	int ret, i;

	if (!cpu_has_feature(CPU_FTR_TM))
		return -ENODEV;

	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
		return -ENODATA;

	/* Flush the state */
	flush_fp_to_thread(target);
	flush_altivec_to_thread(target);
	flush_tmregs_to_thread(target);
	flush_vsx_to_thread(target);

	for (i = 0; i < 32 ; i++)
		buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  buf, 0, 32 * sizeof(double));

	return ret;
}

/**
 * tm_cvsx_set - set CFPR registers
 * @target:	The target task.
 * @regset:	The user regset structure.
 * @pos:	The buffer position.
 * @count:	Number of bytes to copy.
 * @kbuf:	Kernel buffer to copy into.
 * @ubuf:	User buffer to copy from.
 *
 * This function sets in transaction checkpointed VSX registers.
 *
 * When the transaction is active 'fp_state' holds the checkpointed
 * VSX register values for the current transaction to fall back on
 * if it aborts in between. This function sets these checkpointed
 * FPR registers. The userspace interface buffer layout is as follows.
 *
 * struct data {
 *	u64	vsx[32];
 *};
 */
static int tm_cvsx_set(struct task_struct *target,
			const struct user_regset *regset,
			unsigned int pos, unsigned int count,
			const void *kbuf, const void __user *ubuf)
{
	u64 buf[32];
	int ret, i;

	if (!cpu_has_feature(CPU_FTR_TM))
		return -ENODEV;

	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
		return -ENODATA;

	/* Flush the state */
	flush_fp_to_thread(target);
	flush_altivec_to_thread(target);
	flush_tmregs_to_thread(target);
	flush_vsx_to_thread(target);

	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 buf, 0, 32 * sizeof(double));
	for (i = 0; i < 32 ; i++)
		target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];

	return ret;
}
#endif

/*
@@ -1315,6 +1433,7 @@ enum powerpc_regset {
	REGSET_TM_CGPR,		/* TM checkpointed GPR registers */
	REGSET_TM_CFPR,		/* TM checkpointed FPR registers */
	REGSET_TM_CVMX,		/* TM checkpointed VMX registers */
	REGSET_TM_CVSX,		/* TM checkpointed VSX registers */
#endif
};

@@ -1366,6 +1485,11 @@ static const struct user_regset native_regsets[] = {
		.size = sizeof(vector128), .align = sizeof(vector128),
		.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
	},
	[REGSET_TM_CVSX] = {
		.core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
		.size = sizeof(double), .align = sizeof(double),
		.active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set
	},
#endif
};

@@ -1608,6 +1732,11 @@ static const struct user_regset compat_regsets[] = {
		.size = sizeof(vector128), .align = sizeof(vector128),
		.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
	},
	[REGSET_TM_CVSX] = {
		.core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
		.size = sizeof(double), .align = sizeof(double),
		.active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set
	},
#endif
};